aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2014-11-25 21:00:58 +0000
committerEd Maste <emaste@FreeBSD.org>2014-11-25 21:00:58 +0000
commit0cac4ca3916ac24ab6139d03cbfd18db9e715bfe (patch)
treec94307da318be46e5aeea1a325c1e91749506e4f
parent03b99097822ca3ac69252d9afae716a584ed56c4 (diff)
downloadsrc-0cac4ca3916ac24ab6139d03cbfd18db9e715bfe.tar.gz
src-0cac4ca3916ac24ab6139d03cbfd18db9e715bfe.zip
Import LLDB as of upstream SVN r216948 (git 50f7fe44)vendor/lldb/lldb-r216948
This corresponds with the branchpoint for the 3.5 release. A number of files not required for the FreeBSD build have been removed. Sponsored by: DARPA, AFRL
Notes
Notes: svn path=/vendor/lldb/dist/; revision=275072 svn path=/vendor/lldb/lldb-r216948/; revision=275074; tag=vendor/lldb/lldb-r216948
-rw-r--r--include/lldb/API/SBBreakpoint.h8
-rw-r--r--include/lldb/API/SBBreakpointLocation.h6
-rw-r--r--include/lldb/API/SBDefines.h111
-rw-r--r--include/lldb/API/SBError.h2
-rw-r--r--include/lldb/API/SBExpressionOptions.h34
-rw-r--r--include/lldb/API/SBFileSpec.h2
-rw-r--r--include/lldb/API/SBFrame.h2
-rw-r--r--include/lldb/API/SBHostOS.h7
-rw-r--r--include/lldb/API/SBListener.h2
-rw-r--r--include/lldb/API/SBProcess.h6
-rw-r--r--include/lldb/API/SBQueue.h8
-rw-r--r--include/lldb/API/SBQueueItem.h1
-rw-r--r--include/lldb/API/SBStream.h3
-rw-r--r--include/lldb/API/SBTarget.h45
-rw-r--r--include/lldb/API/SBThread.h13
-rw-r--r--include/lldb/API/SBType.h8
-rw-r--r--include/lldb/API/SBTypeEnumMember.h98
-rw-r--r--include/lldb/API/SBUnixSignals.h84
-rw-r--r--include/lldb/API/SBValue.h7
-rw-r--r--include/lldb/Breakpoint/Breakpoint.h2
-rw-r--r--include/lldb/Breakpoint/BreakpointLocationList.h2
-rw-r--r--include/lldb/Breakpoint/BreakpointOptions.h5
-rw-r--r--include/lldb/Breakpoint/BreakpointSite.h11
-rw-r--r--include/lldb/Breakpoint/Watchpoint.h4
-rw-r--r--include/lldb/Core/Address.h6
-rw-r--r--include/lldb/Core/AddressRange.h4
-rw-r--r--include/lldb/Core/ArchSpec.h46
-rw-r--r--include/lldb/Core/ClangForward.h1
-rw-r--r--include/lldb/Core/Communication.h4
-rw-r--r--include/lldb/Core/ConnectionFileDescriptor.h88
-rw-r--r--include/lldb/Core/ConstString.h8
-rw-r--r--include/lldb/Core/DataBuffer.h2
-rw-r--r--include/lldb/Core/DataBufferHeap.h3
-rw-r--r--include/lldb/Core/DataBufferMemoryMap.h11
-rw-r--r--include/lldb/Core/DataEncoder.h6
-rw-r--r--include/lldb/Core/Debugger.h24
-rw-r--r--include/lldb/Core/EmulateInstruction.h20
-rw-r--r--include/lldb/Core/Error.h9
-rw-r--r--include/lldb/Core/IOHandler.h49
-rw-r--r--include/lldb/Core/Listener.h2
-rw-r--r--include/lldb/Core/Mangled.h6
-rw-r--r--include/lldb/Core/Module.h58
-rw-r--r--include/lldb/Core/ModuleList.h15
-rw-r--r--include/lldb/Core/ModuleSpec.h6
-rw-r--r--include/lldb/Core/PluginManager.h23
-rw-r--r--include/lldb/Core/RegisterValue.h6
-rw-r--r--include/lldb/Core/RegularExpression.h12
-rw-r--r--include/lldb/Core/Section.h14
-rw-r--r--include/lldb/Core/SourceManager.h2
-rw-r--r--include/lldb/Core/Stream.h2
-rw-r--r--include/lldb/Core/StructuredData.h486
-rw-r--r--include/lldb/Core/UserID.h6
-rw-r--r--include/lldb/Core/Value.h25
-rw-r--r--include/lldb/Core/ValueObject.h35
-rw-r--r--include/lldb/Core/ValueObjectChild.h5
-rw-r--r--include/lldb/Core/ValueObjectConstResult.h3
-rw-r--r--include/lldb/Core/ValueObjectDynamicValue.h3
-rw-r--r--include/lldb/Core/ValueObjectMemory.h3
-rw-r--r--include/lldb/Core/ValueObjectRegister.h3
-rw-r--r--include/lldb/Core/ValueObjectSyntheticFilter.h3
-rw-r--r--include/lldb/Core/ValueObjectVariable.h3
-rw-r--r--include/lldb/Core/dwarf.h2
-rw-r--r--include/lldb/DataFormatters/CXXFormatterFunctions.h114
-rw-r--r--include/lldb/DataFormatters/FormatManager.h27
-rw-r--r--include/lldb/DataFormatters/TypeFormat.h9
-rw-r--r--include/lldb/DataFormatters/TypeSummary.h18
-rw-r--r--include/lldb/DataFormatters/ValueObjectPrinter.h2
-rw-r--r--include/lldb/Expression/ASTStructExtractor.h2
-rw-r--r--include/lldb/Expression/ClangExpressionDeclMap.h8
-rw-r--r--include/lldb/Expression/ClangExpressionParser.h15
-rw-r--r--include/lldb/Expression/ClangExpressionVariable.h10
-rw-r--r--include/lldb/Expression/ClangFunction.h14
-rw-r--r--include/lldb/Expression/ClangUserExpression.h23
-rw-r--r--include/lldb/Expression/ClangUtilityFunction.h8
-rw-r--r--include/lldb/Expression/DWARFExpression.h13
-rw-r--r--include/lldb/Expression/ExpressionSourceCode.h5
-rw-r--r--include/lldb/Expression/IRExecutionUnit.h87
-rw-r--r--include/lldb/Expression/IRForTarget.h12
-rw-r--r--include/lldb/Expression/IRMemoryMap.h12
-rw-r--r--include/lldb/Host/Condition.h2
-rw-r--r--include/lldb/Host/Config.h2
-rw-r--r--include/lldb/Host/Debug.h244
-rw-r--r--include/lldb/Host/DynamicLibrary.h51
-rw-r--r--include/lldb/Host/Editline.h51
-rw-r--r--include/lldb/Host/Endian.h2
-rw-r--r--include/lldb/Host/File.h20
-rw-r--r--include/lldb/Host/FileCache.h45
-rw-r--r--include/lldb/Host/FileSpec.h78
-rw-r--r--include/lldb/Host/FileSystem.h43
-rw-r--r--include/lldb/Host/Host.h257
-rw-r--r--include/lldb/Host/HostGetOpt.h6
-rw-r--r--include/lldb/Host/HostInfo.h61
-rw-r--r--include/lldb/Host/HostInfoBase.h119
-rw-r--r--include/lldb/Host/HostProcess.h44
-rw-r--r--include/lldb/Host/IOObject.h61
-rw-r--r--include/lldb/Host/OptionParser.h13
-rw-r--r--include/lldb/Host/Pipe.h83
-rw-r--r--include/lldb/Host/Predicate.h12
-rw-r--r--include/lldb/Host/Socket.h103
-rw-r--r--include/lldb/Host/SocketAddress.h6
-rw-r--r--include/lldb/Host/Symbols.h2
-rw-r--r--include/lldb/Host/Terminal.h2
-rw-r--r--include/lldb/Host/TimeValue.h6
-rw-r--r--include/lldb/Host/freebsd/HostInfoFreeBSD.h29
-rw-r--r--include/lldb/Host/posix/HostInfoPosix.h40
-rw-r--r--include/lldb/Host/posix/HostProcessPosix.h46
-rw-r--r--include/lldb/Interpreter/Args.h6
-rw-r--r--include/lldb/Interpreter/CommandCompletions.h2
-rw-r--r--include/lldb/Interpreter/CommandInterpreter.h10
-rw-r--r--include/lldb/Interpreter/CommandObject.h33
-rw-r--r--include/lldb/Interpreter/CommandOptionValidators.h30
-rw-r--r--include/lldb/Interpreter/CommandReturnObject.h13
-rw-r--r--include/lldb/Interpreter/Options.h8
-rw-r--r--include/lldb/Interpreter/PythonDataObjects.h6
-rw-r--r--include/lldb/Interpreter/ScriptInterpreter.h51
-rw-r--r--include/lldb/Interpreter/ScriptInterpreterPython.h41
-rw-r--r--include/lldb/Symbol/Block.h12
-rw-r--r--include/lldb/Symbol/ClangASTContext.h38
-rw-r--r--include/lldb/Symbol/ClangASTImporter.h2
-rw-r--r--include/lldb/Symbol/ClangASTType.h19
-rw-r--r--include/lldb/Symbol/ClangExternalASTSourceCommon.h2
-rw-r--r--include/lldb/Symbol/CompileUnit.h8
-rw-r--r--include/lldb/Symbol/DWARFCallFrameInfo.h2
-rw-r--r--include/lldb/Symbol/Declaration.h4
-rw-r--r--include/lldb/Symbol/FuncUnwinders.h11
-rw-r--r--include/lldb/Symbol/Function.h16
-rw-r--r--include/lldb/Symbol/LineEntry.h4
-rw-r--r--include/lldb/Symbol/LineTable.h4
-rw-r--r--include/lldb/Symbol/ObjectContainer.h4
-rw-r--r--include/lldb/Symbol/ObjectFile.h97
-rw-r--r--include/lldb/Symbol/Symbol.h15
-rw-r--r--include/lldb/Symbol/SymbolContext.h8
-rw-r--r--include/lldb/Symbol/SymbolContextScope.h6
-rw-r--r--include/lldb/Symbol/SymbolFile.h12
-rw-r--r--include/lldb/Symbol/SymbolVendor.h7
-rw-r--r--include/lldb/Symbol/Symtab.h1
-rw-r--r--include/lldb/Symbol/Type.h174
-rw-r--r--include/lldb/Symbol/UnwindPlan.h3
-rw-r--r--include/lldb/Symbol/UnwindTable.h9
-rw-r--r--include/lldb/Symbol/VariableList.h4
-rw-r--r--include/lldb/Target/ABI.h63
-rw-r--r--include/lldb/Target/CPPLanguageRuntime.h2
-rw-r--r--include/lldb/Target/ExecutionContext.h38
-rw-r--r--include/lldb/Target/ExecutionContextScope.h2
-rw-r--r--include/lldb/Target/FileAction.h68
-rw-r--r--include/lldb/Target/JITLoader.h90
-rw-r--r--include/lldb/Target/JITLoaderList.h60
-rw-r--r--include/lldb/Target/MemoryRegionInfo.h104
-rw-r--r--include/lldb/Target/NativeRegisterContext.h190
-rw-r--r--include/lldb/Target/NativeRegisterContextRegisterInfo.h44
-rw-r--r--include/lldb/Target/ObjCLanguageRuntime.h41
-rw-r--r--include/lldb/Target/PathMappingList.h2
-rw-r--r--include/lldb/Target/Platform.h84
-rw-r--r--include/lldb/Target/Process.h977
-rw-r--r--include/lldb/Target/ProcessInfo.h188
-rw-r--r--include/lldb/Target/ProcessLaunchInfo.h225
-rw-r--r--include/lldb/Target/Queue.h13
-rw-r--r--include/lldb/Target/QueueItem.h53
-rw-r--r--include/lldb/Target/QueueList.h4
-rw-r--r--include/lldb/Target/RegisterContext.h43
-rw-r--r--include/lldb/Target/StackFrame.h6
-rw-r--r--include/lldb/Target/StopInfo.h7
-rw-r--r--include/lldb/Target/SystemRuntime.h79
-rw-r--r--include/lldb/Target/Target.h79
-rw-r--r--include/lldb/Target/TargetList.h2
-rw-r--r--include/lldb/Target/Thread.h256
-rw-r--r--include/lldb/Target/ThreadPlan.h38
-rw-r--r--include/lldb/Target/ThreadPlanCallFunction.h8
-rw-r--r--include/lldb/Target/ThreadPlanCallUserExpression.h26
-rw-r--r--include/lldb/Target/ThreadPlanShouldStopHere.h85
-rw-r--r--include/lldb/Target/ThreadPlanStepInRange.h39
-rw-r--r--include/lldb/Target/ThreadPlanStepInstruction.h2
-rw-r--r--include/lldb/Target/ThreadPlanStepOut.h27
-rw-r--r--include/lldb/Target/ThreadPlanStepOverRange.h19
-rw-r--r--include/lldb/Target/ThreadPlanStepRange.h1
-rw-r--r--include/lldb/Target/UnwindAssembly.h5
-rw-r--r--include/lldb/Utility/CleanUp.h6
-rw-r--r--include/lldb/Utility/PseudoTerminal.h4
-rw-r--r--include/lldb/Utility/SafeMachO.h113
-rw-r--r--include/lldb/Utility/SharedCluster.h23
-rw-r--r--include/lldb/Utility/SharingPtr.h15
-rw-r--r--include/lldb/Utility/StringLexer.h62
-rw-r--r--include/lldb/lldb-defines.h23
-rw-r--r--include/lldb/lldb-enumerations.h137
-rw-r--r--include/lldb/lldb-forward.h13
-rw-r--r--include/lldb/lldb-private-enumerations.h46
-rw-r--r--include/lldb/lldb-private-forward.h41
-rw-r--r--include/lldb/lldb-private-interfaces.h6
-rw-r--r--include/lldb/lldb-private-log.h1
-rw-r--r--include/lldb/lldb-private-types.h16
-rw-r--r--include/lldb/lldb-python.h16
-rw-r--r--include/lldb/lldb-types.h41
-rw-r--r--source/API/SBAddress.cpp8
-rw-r--r--source/API/SBBreakpoint.cpp117
-rw-r--r--source/API/SBBreakpointLocation.cpp57
-rw-r--r--source/API/SBBroadcaster.cpp18
-rw-r--r--source/API/SBCommandInterpreter.cpp58
-rw-r--r--source/API/SBCommandReturnObject.cpp14
-rw-r--r--source/API/SBCommunication.cpp52
-rw-r--r--source/API/SBCompileUnit.cpp31
-rw-r--r--source/API/SBData.cpp182
-rw-r--r--source/API/SBDebugger.cpp153
-rw-r--r--source/API/SBDeclaration.cpp21
-rw-r--r--source/API/SBError.cpp12
-rw-r--r--source/API/SBEvent.cpp19
-rw-r--r--source/API/SBExpressionOptions.cpp61
-rw-r--r--source/API/SBFileSpec.cpp30
-rw-r--r--source/API/SBFileSpecList.cpp3
-rw-r--r--source/API/SBFrame.cpp169
-rw-r--r--source/API/SBFunction.cpp12
-rw-r--r--source/API/SBHostOS.cpp26
-rw-r--r--source/API/SBLineEntry.cpp20
-rw-r--r--source/API/SBListener.cpp38
-rw-r--r--source/API/SBModule.cpp49
-rw-r--r--source/API/SBProcess.cpp348
-rw-r--r--source/API/SBQueue.cpp136
-rw-r--r--source/API/SBQueueItem.cpp60
-rw-r--r--source/API/SBStream.cpp2
-rw-r--r--source/API/SBSymbol.cpp6
-rw-r--r--source/API/SBSymbolContext.cpp28
-rw-r--r--source/API/SBTarget.cpp453
-rw-r--r--source/API/SBThread.cpp374
-rw-r--r--source/API/SBType.cpp32
-rw-r--r--source/API/SBTypeEnumMember.cpp192
-rw-r--r--source/API/SBUnixSignals.cpp199
-rw-r--r--source/API/SBValue.cpp406
-rw-r--r--source/API/SBValueList.cpp16
-rw-r--r--source/API/SBWatchpoint.cpp13
-rw-r--r--source/Breakpoint/Breakpoint.cpp2
-rw-r--r--source/Breakpoint/BreakpointID.cpp2
-rw-r--r--source/Breakpoint/BreakpointList.cpp2
-rw-r--r--source/Breakpoint/BreakpointLocation.cpp19
-rw-r--r--source/Breakpoint/BreakpointLocationList.cpp2
-rw-r--r--source/Breakpoint/BreakpointOptions.cpp2
-rw-r--r--source/Breakpoint/BreakpointResolverName.cpp4
-rw-r--r--source/Breakpoint/BreakpointSite.cpp11
-rw-r--r--source/Breakpoint/BreakpointSiteList.cpp2
-rw-r--r--source/Breakpoint/WatchpointList.cpp2
-rw-r--r--source/Commands/CommandCompletions.cpp31
-rw-r--r--source/Commands/CommandObjectArgs.cpp14
-rw-r--r--source/Commands/CommandObjectBreakpoint.cpp95
-rw-r--r--source/Commands/CommandObjectBreakpointCommand.cpp151
-rw-r--r--source/Commands/CommandObjectCommands.cpp41
-rw-r--r--source/Commands/CommandObjectDisassemble.cpp197
-rw-r--r--source/Commands/CommandObjectExpression.cpp94
-rw-r--r--source/Commands/CommandObjectExpression.h3
-rw-r--r--source/Commands/CommandObjectFrame.cpp10
-rw-r--r--source/Commands/CommandObjectHelp.cpp6
-rw-r--r--source/Commands/CommandObjectLog.cpp20
-rw-r--r--source/Commands/CommandObjectMemory.cpp38
-rw-r--r--source/Commands/CommandObjectPlatform.cpp89
-rw-r--r--source/Commands/CommandObjectProcess.cpp144
-rw-r--r--source/Commands/CommandObjectQuit.cpp2
-rw-r--r--source/Commands/CommandObjectRegister.cpp11
-rw-r--r--source/Commands/CommandObjectSettings.cpp9
-rw-r--r--source/Commands/CommandObjectSource.cpp30
-rw-r--r--source/Commands/CommandObjectTarget.cpp749
-rw-r--r--source/Commands/CommandObjectThread.cpp303
-rw-r--r--source/Commands/CommandObjectType.cpp190
-rw-r--r--source/Commands/CommandObjectWatchpoint.cpp46
-rw-r--r--source/Commands/CommandObjectWatchpointCommand.cpp10
-rw-r--r--source/Core/Address.cpp2
-rw-r--r--source/Core/AddressRange.cpp5
-rw-r--r--source/Core/AddressResolverName.cpp2
-rw-r--r--source/Core/ArchSpec.cpp190
-rw-r--r--source/Core/Broadcaster.cpp32
-rw-r--r--source/Core/Communication.cpp16
-rw-r--r--source/Core/ConnectionFileDescriptor.cpp1449
-rw-r--r--source/Core/ConnectionMachPort.cpp4
-rw-r--r--source/Core/ConnectionSharedMemory.cpp12
-rw-r--r--source/Core/ConstString.cpp5
-rw-r--r--source/Core/DataBufferHeap.cpp6
-rw-r--r--source/Core/DataBufferMemoryMap.cpp94
-rw-r--r--source/Core/DataExtractor.cpp55
-rw-r--r--source/Core/Debugger.cpp469
-rw-r--r--source/Core/EmulateInstruction.cpp16
-rw-r--r--source/Core/Error.cpp31
-rw-r--r--source/Core/Event.cpp17
-rw-r--r--source/Core/FastDemangle.cpp2203
-rw-r--r--source/Core/IOHandler.cpp576
-rw-r--r--source/Core/Language.cpp4
-rw-r--r--source/Core/Listener.cpp68
-rw-r--r--source/Core/Log.cpp2
-rw-r--r--source/Core/Mangled.cpp29
-rw-r--r--source/Core/Module.cpp199
-rw-r--r--source/Core/ModuleList.cpp59
-rw-r--r--source/Core/Opcode.cpp2
-rw-r--r--source/Core/PluginManager.cpp198
-rw-r--r--source/Core/RegularExpression.cpp8
-rw-r--r--source/Core/Scalar.cpp22
-rw-r--r--source/Core/SearchFilter.cpp2
-rw-r--r--source/Core/Section.cpp36
-rw-r--r--source/Core/SourceManager.cpp2
-rw-r--r--source/Core/Stream.cpp4
-rw-r--r--source/Core/StructuredData.cpp429
-rw-r--r--source/Core/Value.cpp98
-rw-r--r--source/Core/ValueObject.cpp145
-rw-r--r--source/Core/ValueObjectChild.cpp52
-rw-r--r--source/Core/ValueObjectConstResult.cpp6
-rw-r--r--source/Core/ValueObjectConstResultImpl.cpp6
-rw-r--r--source/Core/ValueObjectDynamicValue.cpp64
-rw-r--r--source/Core/ValueObjectMemory.cpp8
-rw-r--r--source/Core/ValueObjectRegister.cpp6
-rw-r--r--source/Core/ValueObjectSyntheticFilter.cpp6
-rw-r--r--source/Core/ValueObjectVariable.cpp9
-rw-r--r--source/DataFormatters/CF.cpp6
-rw-r--r--source/DataFormatters/CXXFormatterFunctions.cpp116
-rw-r--r--source/DataFormatters/Cocoa.cpp6
-rw-r--r--source/DataFormatters/FormatManager.cpp149
-rw-r--r--source/DataFormatters/LibCxx.cpp10
-rw-r--r--source/DataFormatters/LibCxxList.cpp56
-rw-r--r--source/DataFormatters/LibCxxMap.cpp10
-rw-r--r--source/DataFormatters/LibCxxUnorderedMap.cpp7
-rw-r--r--source/DataFormatters/LibStdcpp.cpp2
-rw-r--r--source/DataFormatters/NSArray.cpp384
-rw-r--r--source/DataFormatters/NSDictionary.cpp12
-rw-r--r--source/DataFormatters/NSSet.cpp6
-rw-r--r--source/DataFormatters/TypeFormat.cpp28
-rw-r--r--source/DataFormatters/TypeSummary.cpp23
-rw-r--r--source/DataFormatters/TypeSynthetic.cpp4
-rw-r--r--source/DataFormatters/ValueObjectPrinter.cpp10
-rw-r--r--source/Expression/ASTResultSynthesizer.cpp218
-rw-r--r--source/Expression/ASTStructExtractor.cpp64
-rw-r--r--source/Expression/ClangASTSource.cpp1010
-rw-r--r--source/Expression/ClangExpressionDeclMap.cpp866
-rw-r--r--source/Expression/ClangExpressionParser.cpp390
-rw-r--r--source/Expression/ClangExpressionVariable.cpp19
-rw-r--r--source/Expression/ClangFunction.cpp88
-rw-r--r--source/Expression/ClangUserExpression.cpp541
-rw-r--r--source/Expression/ClangUtilityFunction.cpp37
-rw-r--r--source/Expression/DWARFExpression.cpp243
-rw-r--r--source/Expression/ExpressionSourceCode.cpp55
-rw-r--r--source/Expression/IRDynamicChecks.cpp213
-rw-r--r--source/Expression/IRExecutionUnit.cpp497
-rw-r--r--source/Expression/IRForTarget.cpp1437
-rw-r--r--source/Expression/IRInterpreter.cpp519
-rw-r--r--source/Expression/IRMemoryMap.cpp274
-rw-r--r--source/Expression/Materializer.cpp96
-rw-r--r--source/Host/common/Condition.cpp5
-rw-r--r--source/Host/common/DynamicLibrary.cpp33
-rw-r--r--source/Host/common/Editline.cpp418
-rw-r--r--source/Host/common/File.cpp39
-rw-r--r--source/Host/common/FileCache.cpp127
-rw-r--r--source/Host/common/FileSpec.cpp381
-rw-r--r--source/Host/common/Host.cpp1282
-rw-r--r--source/Host/common/HostInfoBase.cpp318
-rw-r--r--source/Host/common/IOObject.cpp14
-rw-r--r--source/Host/common/Mutex.cpp4
-rw-r--r--source/Host/common/NativeBreakpoint.cpp116
-rw-r--r--source/Host/common/NativeBreakpoint.h66
-rw-r--r--source/Host/common/NativeBreakpointList.cpp199
-rw-r--r--source/Host/common/NativeBreakpointList.h53
-rw-r--r--source/Host/common/NativeProcessProtocol.cpp412
-rw-r--r--source/Host/common/NativeProcessProtocol.h333
-rw-r--r--source/Host/common/NativeThreadProtocol.cpp97
-rw-r--r--source/Host/common/NativeThreadProtocol.h85
-rw-r--r--source/Host/common/OptionParser.cpp21
-rw-r--r--source/Host/common/Pipe.cpp171
-rw-r--r--source/Host/common/Socket.cpp662
-rw-r--r--source/Host/common/SocketAddress.cpp3
-rw-r--r--source/Host/common/SoftwareBreakpoint.cpp296
-rw-r--r--source/Host/common/SoftwareBreakpoint.h51
-rw-r--r--source/Host/common/Terminal.cpp5
-rw-r--r--source/Host/freebsd/Host.cpp102
-rw-r--r--source/Host/freebsd/HostInfoFreeBSD.cpp85
-rw-r--r--source/Host/posix/FileSystem.cpp201
-rw-r--r--source/Host/posix/HostInfoPosix.cpp193
-rw-r--r--source/Host/posix/HostProcessPosix.cpp103
-rw-r--r--source/Interpreter/Args.cpp125
-rw-r--r--source/Interpreter/CommandHistory.cpp20
-rw-r--r--source/Interpreter/CommandInterpreter.cpp195
-rw-r--r--source/Interpreter/CommandObject.cpp213
-rw-r--r--source/Interpreter/CommandObjectRegexCommand.cpp6
-rw-r--r--source/Interpreter/CommandObjectScript.cpp4
-rw-r--r--source/Interpreter/CommandOptionValidators.cpp39
-rw-r--r--source/Interpreter/CommandReturnObject.cpp20
-rw-r--r--source/Interpreter/OptionGroupArchitecture.cpp2
-rw-r--r--source/Interpreter/OptionGroupBoolean.cpp3
-rw-r--r--source/Interpreter/OptionGroupFile.cpp6
-rw-r--r--source/Interpreter/OptionGroupFormat.cpp10
-rw-r--r--source/Interpreter/OptionGroupOutputFile.cpp10
-rw-r--r--source/Interpreter/OptionGroupPlatform.cpp8
-rw-r--r--source/Interpreter/OptionGroupString.cpp3
-rw-r--r--source/Interpreter/OptionGroupUInt64.cpp3
-rw-r--r--source/Interpreter/OptionGroupUUID.cpp2
-rw-r--r--source/Interpreter/OptionGroupValueObjectDisplay.cpp26
-rw-r--r--source/Interpreter/OptionGroupVariable.cpp16
-rw-r--r--source/Interpreter/OptionGroupWatchpoint.cpp8
-rw-r--r--source/Interpreter/OptionValue.cpp68
-rw-r--r--source/Interpreter/OptionValueArch.cpp2
-rw-r--r--source/Interpreter/OptionValueArray.cpp7
-rw-r--r--source/Interpreter/OptionValueBoolean.cpp5
-rw-r--r--source/Interpreter/OptionValueDictionary.cpp14
-rw-r--r--source/Interpreter/OptionValueEnumeration.cpp2
-rw-r--r--source/Interpreter/OptionValueFileSpec.cpp3
-rw-r--r--source/Interpreter/OptionValueFormat.cpp2
-rw-r--r--source/Interpreter/OptionValueProperties.cpp37
-rw-r--r--source/Interpreter/OptionValueUUID.cpp2
-rw-r--r--source/Interpreter/Options.cpp77
-rw-r--r--source/Interpreter/Property.cpp4
-rw-r--r--source/Interpreter/PythonDataObjects.cpp24
-rw-r--r--source/Interpreter/ScriptInterpreter.cpp35
-rw-r--r--source/Interpreter/ScriptInterpreterPython.cpp378
-rw-r--r--source/Interpreter/embedded_interpreter.py4
-rw-r--r--source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp13
-rw-r--r--source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp1103
-rw-r--r--source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h145
-rw-r--r--source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp10
-rw-r--r--source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp554
-rw-r--r--source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h148
-rw-r--r--source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp29
-rw-r--r--source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp140
-rw-r--r--source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h46
-rw-r--r--source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp727
-rw-r--r--source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h182
-rw-r--r--source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp403
-rw-r--r--source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h279
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp9
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp60
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp2
-rw-r--r--source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h1
-rw-r--r--source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp31
-rw-r--r--source/Plugins/Instruction/ARM/EmulateInstructionARM.h2
-rw-r--r--source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp719
-rw-r--r--source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h297
-rw-r--r--source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp430
-rw-r--r--source/Plugins/JITLoader/GDB/JITLoaderGDB.h104
-rw-r--r--source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp6
-rw-r--r--source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp35
-rw-r--r--source/Plugins/ObjectFile/ELF/ELFHeader.cpp6
-rw-r--r--source/Plugins/ObjectFile/ELF/ELFHeader.h8
-rw-r--r--source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp838
-rw-r--r--source/Plugins/ObjectFile/ELF/ObjectFileELF.h55
-rw-r--r--source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp363
-rw-r--r--source/Plugins/ObjectFile/JIT/ObjectFileJIT.h142
-rw-r--r--source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp66
-rw-r--r--source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h2
-rw-r--r--source/Plugins/Platform/POSIX/PlatformPOSIX.cpp216
-rw-r--r--source/Plugins/Platform/POSIX/PlatformPOSIX.h41
-rw-r--r--source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp33
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp27
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessMonitor.cpp17
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessMonitor.h7
-rw-r--r--source/Plugins/Process/POSIX/POSIXThread.cpp120
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIX.cpp66
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIX.h19
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp318
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h95
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp3
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h4
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp12
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h4
-rw-r--r--source/Plugins/Process/Utility/ARMDefines.h2
-rw-r--r--source/Plugins/Process/Utility/ARMUtils.h2
-rw-r--r--source/Plugins/Process/Utility/DynamicRegisterInfo.cpp18
-rw-r--r--source/Plugins/Process/Utility/FreeBSDSignals.cpp31
-rw-r--r--source/Plugins/Process/Utility/FreeBSDSignals.h28
-rw-r--r--source/Plugins/Process/Utility/HistoryThread.cpp14
-rw-r--r--source/Plugins/Process/Utility/HistoryUnwind.cpp6
-rw-r--r--source/Plugins/Process/Utility/InferiorCallPOSIX.cpp12
-rw-r--r--source/Plugins/Process/Utility/InstructionUtils.h2
-rw-r--r--source/Plugins/Process/Utility/LinuxSignals.cpp62
-rw-r--r--source/Plugins/Process/Utility/LinuxSignals.h35
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp16
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_arm.h2
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp944
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h296
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp13
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_i386.h2
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp14
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h2
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDummy.cpp2
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDummy.h2
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp (renamed from source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp)20
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h (renamed from source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.h)10
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp (renamed from source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.cpp)15
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h (renamed from source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.h)10
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp (renamed from source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp)69
-rw-r--r--source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h (renamed from source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h)14
-rw-r--r--source/Plugins/Process/Utility/RegisterContextHistory.cpp2
-rw-r--r--source/Plugins/Process/Utility/RegisterContextHistory.h2
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.cpp49
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.h4
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp89
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_arm64.h81
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp (renamed from source/Plugins/Process/POSIX/RegisterContextLinux_i386.cpp)57
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_i386.h (renamed from source/Plugins/Process/POSIX/RegisterContextLinux_i386.h)10
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp (renamed from source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp)70
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h (renamed from source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h)14
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp4
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h2
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMemory.cpp2
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMemory.h2
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX.h (renamed from source/Plugins/Process/POSIX/RegisterContextPOSIX.h)21
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp299
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h272
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp (renamed from source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.cpp)3
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h (renamed from source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h)6
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp (renamed from source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.cpp)49
-rw-r--r--source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h (renamed from source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.h)6
-rw-r--r--source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp2
-rw-r--r--source/Plugins/Process/Utility/RegisterContextThreadMemory.h2
-rw-r--r--source/Plugins/Process/Utility/RegisterContext_mips64.h (renamed from source/Plugins/Process/POSIX/RegisterContext_mips64.h)0
-rw-r--r--source/Plugins/Process/Utility/RegisterContext_x86.h (renamed from source/Plugins/Process/POSIX/RegisterContext_x86.h)14
-rw-r--r--source/Plugins/Process/Utility/RegisterInfoInterface.h49
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_arm64.h347
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_i386.h (renamed from source/Plugins/Process/POSIX/RegisterInfos_i386.h)14
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_mips64.h (renamed from source/Plugins/Process/POSIX/RegisterInfos_mips64.h)4
-rw-r--r--source/Plugins/Process/Utility/RegisterInfos_x86_64.h (renamed from source/Plugins/Process/POSIX/RegisterInfos_x86_64.h)20
-rw-r--r--source/Plugins/Process/Utility/StopInfoMachException.cpp68
-rw-r--r--source/Plugins/Process/Utility/UnwindLLDB.cpp2
-rw-r--r--source/Plugins/Process/Utility/lldb-x86-register-enums.h292
-rw-r--r--source/Plugins/Process/elf-core/ProcessElfCore.cpp71
-rw-r--r--source/Plugins/Process/elf-core/ProcessElfCore.h48
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp22
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h8
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h4
-rw-r--r--source/Plugins/Process/elf-core/ThreadElfCore.cpp6
-rw-r--r--source/Plugins/Process/elf-core/ThreadElfCore.h2
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp175
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h2
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp386
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h53
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp2993
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h210
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp328
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h2
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp397
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.h25
-rw-r--r--source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp52
-rw-r--r--source/Plugins/Process/gdb-remote/ThreadGDBRemote.h10
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp94
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h9
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp53
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h3
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp94
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp5
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp55
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp34
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h10
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp16
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp5
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp2
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp2
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp2
-rw-r--r--source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h16
-rw-r--r--source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp4
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp528
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h9
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp41
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h4
-rw-r--r--source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp16
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp17
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h5
-rw-r--r--source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp475
-rw-r--r--source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h5
-rw-r--r--source/Symbol/Block.cpp46
-rw-r--r--source/Symbol/ClangASTContext.cpp438
-rw-r--r--source/Symbol/ClangASTImporter.cpp178
-rw-r--r--source/Symbol/ClangASTType.cpp2158
-rw-r--r--source/Symbol/ClangExternalASTSourceCallbacks.cpp2
-rw-r--r--source/Symbol/ClangExternalASTSourceCommon.cpp2
-rw-r--r--source/Symbol/CompileUnit.cpp16
-rw-r--r--source/Symbol/DWARFCallFrameInfo.cpp62
-rw-r--r--source/Symbol/FuncUnwinders.cpp61
-rw-r--r--source/Symbol/Function.cpp46
-rw-r--r--source/Symbol/LineTable.cpp30
-rw-r--r--source/Symbol/ObjectFile.cpp115
-rw-r--r--source/Symbol/Symbol.cpp144
-rw-r--r--source/Symbol/SymbolContext.cpp108
-rw-r--r--source/Symbol/SymbolFile.cpp6
-rw-r--r--source/Symbol/SymbolVendor.cpp33
-rw-r--r--source/Symbol/Symtab.cpp80
-rw-r--r--source/Symbol/Type.cpp313
-rw-r--r--source/Symbol/TypeList.cpp43
-rw-r--r--source/Symbol/UnwindPlan.cpp25
-rw-r--r--source/Symbol/UnwindTable.cpp34
-rw-r--r--source/Symbol/Variable.cpp26
-rw-r--r--source/Target/ABI.cpp34
-rw-r--r--source/Target/FileAction.cpp95
-rw-r--r--source/Target/JITLoader.cpp38
-rw-r--r--source/Target/JITLoaderList.cpp77
-rw-r--r--source/Target/LanguageRuntime.cpp12
-rw-r--r--source/Target/Memory.cpp36
-rw-r--r--source/Target/NativeRegisterContext.cpp470
-rw-r--r--source/Target/NativeRegisterContextRegisterInfo.cpp44
-rw-r--r--source/Target/ObjCLanguageRuntime.cpp23
-rw-r--r--source/Target/PathMappingList.cpp4
-rw-r--r--source/Target/Platform.cpp103
-rw-r--r--source/Target/Process.cpp1458
-rw-r--r--source/Target/ProcessInfo.cpp138
-rw-r--r--source/Target/ProcessLaunchInfo.cpp459
-rw-r--r--source/Target/Queue.cpp15
-rw-r--r--source/Target/QueueItem.cpp85
-rw-r--r--source/Target/RegisterContext.cpp4
-rw-r--r--source/Target/SectionLoadHistory.cpp19
-rw-r--r--source/Target/SectionLoadList.cpp31
-rw-r--r--source/Target/StackFrame.cpp15
-rw-r--r--source/Target/StackFrameList.cpp4
-rw-r--r--source/Target/StackID.cpp5
-rw-r--r--source/Target/StopInfo.cpp106
-rw-r--r--source/Target/Target.cpp127
-rw-r--r--source/Target/TargetList.cpp183
-rw-r--r--source/Target/Thread.cpp335
-rw-r--r--source/Target/ThreadList.cpp11
-rw-r--r--source/Target/ThreadPlan.cpp15
-rw-r--r--source/Target/ThreadPlanBase.cpp4
-rw-r--r--source/Target/ThreadPlanCallFunction.cpp97
-rw-r--r--source/Target/ThreadPlanCallUserExpression.cpp52
-rw-r--r--source/Target/ThreadPlanRunToAddress.cpp2
-rw-r--r--source/Target/ThreadPlanShouldStopHere.cpp142
-rw-r--r--source/Target/ThreadPlanStepInRange.cpp132
-rw-r--r--source/Target/ThreadPlanStepInstruction.cpp94
-rw-r--r--source/Target/ThreadPlanStepOut.cpp179
-rw-r--r--source/Target/ThreadPlanStepOverRange.cpp58
-rw-r--r--source/Target/ThreadPlanStepRange.cpp19
-rw-r--r--source/Target/ThreadPlanStepUntil.cpp2
-rw-r--r--source/Target/ThreadPlanTracer.cpp11
-rw-r--r--source/Utility/ARM64_DWARF_Registers.cpp148
-rw-r--r--source/Utility/ARM64_DWARF_Registers.h102
-rw-r--r--source/Utility/ARM64_GCC_Registers.h92
-rw-r--r--source/Utility/ARM_DWARF_Registers.cpp2
-rw-r--r--source/Utility/PseudoTerminal.cpp9
-rw-r--r--source/Utility/SharingPtr.cpp4
-rw-r--r--source/Utility/StringExtractor.cpp31
-rw-r--r--source/Utility/StringExtractor.h5
-rw-r--r--source/Utility/StringExtractorGDBRemote.cpp6
-rw-r--r--source/Utility/StringExtractorGDBRemote.h3
-rw-r--r--source/Utility/StringLexer.cpp101
-rw-r--r--source/Utility/TimeSpecTimeout.h2
-rw-r--r--source/lldb-log.cpp5
-rw-r--r--source/lldb.cpp75
-rw-r--r--tools/driver/Driver.cpp242
-rw-r--r--tools/driver/Driver.h5
-rw-r--r--tools/driver/Platform.cpp25
-rw-r--r--tools/driver/Platform.h56
-rw-r--r--tools/lldb-mi/Driver.cpp1299
-rw-r--r--tools/lldb-mi/Driver.h163
-rw-r--r--tools/lldb-mi/MICmdArgContext.cpp255
-rw-r--r--tools/lldb-mi/MICmdArgContext.h61
-rw-r--r--tools/lldb-mi/MICmdArgSet.cpp420
-rw-r--r--tools/lldb-mi/MICmdArgSet.h109
-rw-r--r--tools/lldb-mi/MICmdArgValBase.cpp171
-rw-r--r--tools/lldb-mi/MICmdArgValBase.h157
-rw-r--r--tools/lldb-mi/MICmdArgValConsume.cpp119
-rw-r--r--tools/lldb-mi/MICmdArgValConsume.h63
-rw-r--r--tools/lldb-mi/MICmdArgValFile.cpp204
-rw-r--r--tools/lldb-mi/MICmdArgValFile.h61
-rw-r--r--tools/lldb-mi/MICmdArgValListBase.cpp221
-rw-r--r--tools/lldb-mi/MICmdArgValListBase.h103
-rw-r--r--tools/lldb-mi/MICmdArgValListOfN.cpp189
-rw-r--r--tools/lldb-mi/MICmdArgValListOfN.h98
-rw-r--r--tools/lldb-mi/MICmdArgValNumber.cpp167
-rw-r--r--tools/lldb-mi/MICmdArgValNumber.h65
-rw-r--r--tools/lldb-mi/MICmdArgValOptionLong.cpp319
-rw-r--r--tools/lldb-mi/MICmdArgValOptionLong.h109
-rw-r--r--tools/lldb-mi/MICmdArgValOptionShort.cpp128
-rw-r--r--tools/lldb-mi/MICmdArgValOptionShort.h65
-rw-r--r--tools/lldb-mi/MICmdArgValString.cpp502
-rw-r--r--tools/lldb-mi/MICmdArgValString.h76
-rw-r--r--tools/lldb-mi/MICmdArgValThreadGrp.cpp173
-rw-r--r--tools/lldb-mi/MICmdArgValThreadGrp.h66
-rw-r--r--tools/lldb-mi/MICmdBase.cpp263
-rw-r--r--tools/lldb-mi/MICmdBase.h156
-rw-r--r--tools/lldb-mi/MICmdCmd.cpp174
-rw-r--r--tools/lldb-mi/MICmdCmd.h104
-rw-r--r--tools/lldb-mi/MICmdCmdBreak.cpp1026
-rw-r--r--tools/lldb-mi/MICmdCmdBreak.h292
-rw-r--r--tools/lldb-mi/MICmdCmdData.cpp1365
-rw-r--r--tools/lldb-mi/MICmdCmdData.h374
-rw-r--r--tools/lldb-mi/MICmdCmdEnviro.cpp143
-rw-r--r--tools/lldb-mi/MICmdCmdEnviro.h69
-rw-r--r--tools/lldb-mi/MICmdCmdExec.cpp982
-rw-r--r--tools/lldb-mi/MICmdCmdExec.h310
-rw-r--r--tools/lldb-mi/MICmdCmdFile.cpp184
-rw-r--r--tools/lldb-mi/MICmdCmdFile.h71
-rw-r--r--tools/lldb-mi/MICmdCmdGdbInfo.cpp232
-rw-r--r--tools/lldb-mi/MICmdCmdGdbInfo.h93
-rw-r--r--tools/lldb-mi/MICmdCmdGdbSet.cpp260
-rw-r--r--tools/lldb-mi/MICmdCmdGdbSet.h96
-rw-r--r--tools/lldb-mi/MICmdCmdGdbThread.cpp100
-rw-r--r--tools/lldb-mi/MICmdCmdGdbThread.h61
-rw-r--r--tools/lldb-mi/MICmdCmdMiscellanous.cpp588
-rw-r--r--tools/lldb-mi/MICmdCmdMiscellanous.h175
-rw-r--r--tools/lldb-mi/MICmdCmdStack.cpp634
-rw-r--r--tools/lldb-mi/MICmdCmdStack.h184
-rw-r--r--tools/lldb-mi/MICmdCmdSupportInfo.cpp129
-rw-r--r--tools/lldb-mi/MICmdCmdSupportInfo.h69
-rw-r--r--tools/lldb-mi/MICmdCmdSupportList.cpp102
-rw-r--r--tools/lldb-mi/MICmdCmdSupportList.h63
-rw-r--r--tools/lldb-mi/MICmdCmdTarget.cpp217
-rw-r--r--tools/lldb-mi/MICmdCmdTarget.h70
-rw-r--r--tools/lldb-mi/MICmdCmdThread.cpp207
-rw-r--r--tools/lldb-mi/MICmdCmdThread.h76
-rw-r--r--tools/lldb-mi/MICmdCmdTrace.cpp99
-rw-r--r--tools/lldb-mi/MICmdCmdTrace.h61
-rw-r--r--tools/lldb-mi/MICmdCmdVar.cpp1492
-rw-r--r--tools/lldb-mi/MICmdCmdVar.h382
-rw-r--r--tools/lldb-mi/MICmdCommands.cpp135
-rw-r--r--tools/lldb-mi/MICmdCommands.h36
-rw-r--r--tools/lldb-mi/MICmdData.cpp24
-rw-r--r--tools/lldb-mi/MICmdData.h74
-rw-r--r--tools/lldb-mi/MICmdFactory.cpp229
-rw-r--r--tools/lldb-mi/MICmdFactory.h99
-rw-r--r--tools/lldb-mi/MICmdInterpreter.cpp301
-rw-r--r--tools/lldb-mi/MICmdInterpreter.h78
-rw-r--r--tools/lldb-mi/MICmdInvoker.cpp333
-rw-r--r--tools/lldb-mi/MICmdInvoker.h118
-rw-r--r--tools/lldb-mi/MICmdMgr.cpp257
-rw-r--r--tools/lldb-mi/MICmdMgr.h83
-rw-r--r--tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.cpp110
-rw-r--r--tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.h88
-rw-r--r--tools/lldb-mi/MICmnBase.cpp144
-rw-r--r--tools/lldb-mi/MICmnBase.h60
-rw-r--r--tools/lldb-mi/MICmnConfig.h50
-rw-r--r--tools/lldb-mi/MICmnLLDBBroadcaster.cpp89
-rw-r--r--tools/lldb-mi/MICmnLLDBBroadcaster.h61
-rw-r--r--tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp1312
-rw-r--r--tools/lldb-mi/MICmnLLDBDebugSessionInfo.h236
-rw-r--r--tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.cpp570
-rw-r--r--tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.h139
-rw-r--r--tools/lldb-mi/MICmnLLDBDebugger.cpp707
-rw-r--r--tools/lldb-mi/MICmnLLDBDebugger.h125
-rw-r--r--tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp1566
-rw-r--r--tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h97
-rw-r--r--tools/lldb-mi/MICmnLLDBProxySBValue.cpp153
-rw-r--r--tools/lldb-mi/MICmnLLDBProxySBValue.h47
-rw-r--r--tools/lldb-mi/MICmnLLDBUtilSBValue.cpp324
-rw-r--r--tools/lldb-mi/MICmnLLDBUtilSBValue.h71
-rw-r--r--tools/lldb-mi/MICmnLog.cpp355
-rw-r--r--tools/lldb-mi/MICmnLog.h143
-rw-r--r--tools/lldb-mi/MICmnLogMediumFile.cpp420
-rw-r--r--tools/lldb-mi/MICmnLogMediumFile.h96
-rw-r--r--tools/lldb-mi/MICmnMIOutOfBandRecord.cpp161
-rw-r--r--tools/lldb-mi/MICmnMIOutOfBandRecord.h110
-rw-r--r--tools/lldb-mi/MICmnMIResultRecord.cpp142
-rw-r--r--tools/lldb-mi/MICmnMIResultRecord.h106
-rw-r--r--tools/lldb-mi/MICmnMIValue.cpp64
-rw-r--r--tools/lldb-mi/MICmnMIValue.h64
-rw-r--r--tools/lldb-mi/MICmnMIValueConst.cpp98
-rw-r--r--tools/lldb-mi/MICmnMIValueConst.h72
-rw-r--r--tools/lldb-mi/MICmnMIValueList.cpp203
-rw-r--r--tools/lldb-mi/MICmnMIValueList.h70
-rw-r--r--tools/lldb-mi/MICmnMIValueResult.cpp141
-rw-r--r--tools/lldb-mi/MICmnMIValueResult.h75
-rw-r--r--tools/lldb-mi/MICmnMIValueTuple.cpp227
-rw-r--r--tools/lldb-mi/MICmnMIValueTuple.h76
-rw-r--r--tools/lldb-mi/MICmnResources.cpp409
-rw-r--r--tools/lldb-mi/MICmnResources.h351
-rw-r--r--tools/lldb-mi/MICmnStreamStderr.cpp257
-rw-r--r--tools/lldb-mi/MICmnStreamStderr.h76
-rw-r--r--tools/lldb-mi/MICmnStreamStdin.cpp421
-rw-r--r--tools/lldb-mi/MICmnStreamStdin.h125
-rw-r--r--tools/lldb-mi/MICmnStreamStdinLinux.cpp212
-rw-r--r--tools/lldb-mi/MICmnStreamStdinLinux.h75
-rw-r--r--tools/lldb-mi/MICmnStreamStdinWindows.cpp279
-rw-r--r--tools/lldb-mi/MICmnStreamStdinWindows.h81
-rw-r--r--tools/lldb-mi/MICmnStreamStdout.cpp230
-rw-r--r--tools/lldb-mi/MICmnStreamStdout.h75
-rw-r--r--tools/lldb-mi/MICmnThreadMgrStd.cpp167
-rw-r--r--tools/lldb-mi/MICmnThreadMgrStd.h134
-rw-r--r--tools/lldb-mi/MIDataTypes.h100
-rw-r--r--tools/lldb-mi/MIDriver.cpp1276
-rw-r--r--tools/lldb-mi/MIDriver.h182
-rw-r--r--tools/lldb-mi/MIDriverBase.cpp195
-rw-r--r--tools/lldb-mi/MIDriverBase.h78
-rw-r--r--tools/lldb-mi/MIDriverMain.cpp393
-rw-r--r--tools/lldb-mi/MIDriverMgr.cpp762
-rw-r--r--tools/lldb-mi/MIDriverMgr.h138
-rw-r--r--tools/lldb-mi/MIReadMe.txt261
-rw-r--r--tools/lldb-mi/MIUtilDateTimeStd.cpp84
-rw-r--r--tools/lldb-mi/MIUtilDateTimeStd.h55
-rw-r--r--tools/lldb-mi/MIUtilDebug.cpp128
-rw-r--r--tools/lldb-mi/MIUtilDebug.h96
-rw-r--r--tools/lldb-mi/MIUtilFileStd.cpp290
-rw-r--r--tools/lldb-mi/MIUtilFileStd.h65
-rw-r--r--tools/lldb-mi/MIUtilMapIdToVariant.cpp124
-rw-r--r--tools/lldb-mi/MIUtilMapIdToVariant.h148
-rw-r--r--tools/lldb-mi/MIUtilSingletonBase.h71
-rw-r--r--tools/lldb-mi/MIUtilSingletonHelper.h95
-rw-r--r--tools/lldb-mi/MIUtilString.cpp680
-rw-r--r--tools/lldb-mi/MIUtilString.h85
-rw-r--r--tools/lldb-mi/MIUtilSystemLinux.cpp119
-rw-r--r--tools/lldb-mi/MIUtilSystemLinux.h57
-rw-r--r--tools/lldb-mi/MIUtilSystemOsx.cpp125
-rw-r--r--tools/lldb-mi/MIUtilSystemOsx.h57
-rw-r--r--tools/lldb-mi/MIUtilSystemWindows.cpp151
-rw-r--r--tools/lldb-mi/MIUtilSystemWindows.h56
-rw-r--r--tools/lldb-mi/MIUtilTermios.cpp69
-rw-r--r--tools/lldb-mi/MIUtilTermios.h30
-rw-r--r--tools/lldb-mi/MIUtilThreadBaseStd.cpp339
-rw-r--r--tools/lldb-mi/MIUtilThreadBaseStd.h170
-rw-r--r--tools/lldb-mi/MIUtilVariant.cpp392
-rw-r--r--tools/lldb-mi/MIUtilVariant.h288
-rw-r--r--tools/lldb-mi/Platform.cpp109
-rw-r--r--tools/lldb-mi/Platform.h109
-rw-r--r--tools/lldb-platform/lldb-platform.cpp7
797 files changed, 82260 insertions, 16499 deletions
diff --git a/include/lldb/API/SBBreakpoint.h b/include/lldb/API/SBBreakpoint.h
index be9c499798e1..86d49c29a821 100644
--- a/include/lldb/API/SBBreakpoint.h
+++ b/include/lldb/API/SBBreakpoint.h
@@ -117,7 +117,13 @@ public:
void
SetCallback (BreakpointHitCallback callback, void *baton);
-
+
+ void
+ SetScriptCallbackFunction (const char *callback_function_name);
+
+ SBError
+ SetScriptCallbackBody (const char *script_body_text);
+
size_t
GetNumResolvedLocations() const;
diff --git a/include/lldb/API/SBBreakpointLocation.h b/include/lldb/API/SBBreakpointLocation.h
index 3b2ca2cf88e8..fd9f246de4ff 100644
--- a/include/lldb/API/SBBreakpointLocation.h
+++ b/include/lldb/API/SBBreakpointLocation.h
@@ -59,6 +59,12 @@ public:
GetCondition ();
void
+ SetScriptCallbackFunction (const char *callback_function_name);
+
+ SBError
+ SetScriptCallbackBody (const char *script_body_text);
+
+ void
SetThreadID (lldb::tid_t sb_thread_id);
lldb::tid_t
diff --git a/include/lldb/API/SBDefines.h b/include/lldb/API/SBDefines.h
index 8779d43d1f40..30ea0dfda56e 100644
--- a/include/lldb/API/SBDefines.h
+++ b/include/lldb/API/SBDefines.h
@@ -21,62 +21,71 @@
#include "lldb/lldb-types.h"
#include "lldb/lldb-versioning.h"
-// Forward Declarations
+#ifdef SWIG
+#define LLDB_API
+#endif
+// Forward Declarations
namespace lldb {
-class SBAddress;
-class SBBlock;
-class SBBreakpoint;
-class SBBreakpointLocation;
-class SBBroadcaster;
-class SBCommand;
-class SBCommandInterpreter;
-class SBCommandPluginInterface;
-class SBCommandReturnObject;
-class SBCommunication;
-class SBCompileUnit;
-class SBData;
-class SBDebugger;
-class SBDeclaration;
-class SBError;
-class SBEvent;
-class SBEventList;
-class SBExpressionOptions;
-class SBFileSpec;
-class SBFileSpecList;
-class SBFrame;
-class SBFunction;
-class SBHostOS;
-class SBInstruction;
-class SBInstructionList;
-class SBLineEntry;
-class SBListener;
-class SBModule;
-class SBModuleSpec;
-class SBModuleSpecList;
-class SBProcess;
-class SBSourceManager;
-class SBStream;
-class SBStringList;
-class SBSymbol;
-class SBSymbolContext;
-class SBSymbolContextList;
-class SBTarget;
-class SBThread;
-class SBType;
-class SBTypeCategory;
-class SBTypeFilter;
-class SBTypeFormat;
-class SBTypeNameSpecifier;
-class SBTypeSummary;
+class LLDB_API SBAddress;
+class LLDB_API SBBlock;
+class LLDB_API SBBreakpoint;
+class LLDB_API SBBreakpointLocation;
+class LLDB_API SBBroadcaster;
+class LLDB_API SBCommand;
+class LLDB_API SBCommandInterpreter;
+class LLDB_API SBCommandPluginInterface;
+class LLDB_API SBCommandReturnObject;
+class LLDB_API SBCommunication;
+class LLDB_API SBCompileUnit;
+class LLDB_API SBData;
+class LLDB_API SBDebugger;
+class LLDB_API SBDeclaration;
+class LLDB_API SBError;
+class LLDB_API SBEvent;
+class LLDB_API SBEventList;
+class LLDB_API SBExpressionOptions;
+class LLDB_API SBFileSpec;
+class LLDB_API SBFileSpecList;
+class LLDB_API SBFrame;
+class LLDB_API SBFunction;
+class LLDB_API SBHostOS;
+class LLDB_API SBInstruction;
+class LLDB_API SBInstructionList;
+class LLDB_API SBLineEntry;
+class LLDB_API SBListener;
+class LLDB_API SBModule;
+class LLDB_API SBModuleSpec;
+class LLDB_API SBModuleSpecList;
+class LLDB_API SBProcess;
+class LLDB_API SBQueue;
+class LLDB_API SBQueueItem;
+class LLDB_API SBSection;
+class LLDB_API SBSourceManager;
+class LLDB_API SBStream;
+class LLDB_API SBStringList;
+class LLDB_API SBSymbol;
+class LLDB_API SBSymbolContext;
+class LLDB_API SBSymbolContextList;
+class LLDB_API SBTarget;
+class LLDB_API SBThread;
+class LLDB_API SBType;
+class LLDB_API SBTypeCategory;
+class LLDB_API SBTypeEnumMember;
+class LLDB_API SBTypeEnumMemberList;
+class LLDB_API SBTypeFilter;
+class LLDB_API SBTypeFormat;
+class LLDB_API SBTypeNameSpecifier;
+class LLDB_API SBTypeSummary;
#ifndef LLDB_DISABLE_PYTHON
-class SBTypeSynthetic;
+class LLDB_API SBTypeSynthetic;
#endif
-class SBTypeList;
-class SBValue;
-class SBValueList;
-class SBWatchpoint;
+class LLDB_API SBTypeList;
+class LLDB_API SBValue;
+class LLDB_API SBValueList;
+class LLDB_API SBWatchpoint;
+class LLDB_API SBUnixSignals;
}
diff --git a/include/lldb/API/SBError.h b/include/lldb/API/SBError.h
index 25d7e81a3be5..b9908658c5bc 100644
--- a/include/lldb/API/SBError.h
+++ b/include/lldb/API/SBError.h
@@ -77,6 +77,8 @@ protected:
friend class SBTarget;
friend class SBValue;
friend class SBWatchpoint;
+ friend class SBBreakpoint;
+ friend class SBBreakpointLocation;
lldb_private::Error *
get();
diff --git a/include/lldb/API/SBExpressionOptions.h b/include/lldb/API/SBExpressionOptions.h
index 6a3a640432f6..c3592880c46a 100644
--- a/include/lldb/API/SBExpressionOptions.h
+++ b/include/lldb/API/SBExpressionOptions.h
@@ -56,20 +56,54 @@ public:
uint32_t
GetTimeoutInMicroSeconds () const;
+ // Set the timeout for the expression, 0 means wait forever.
void
SetTimeoutInMicroSeconds (uint32_t timeout = 0);
+ uint32_t
+ GetOneThreadTimeoutInMicroSeconds () const;
+
+ // Set the timeout for running on one thread, 0 means use the default behavior.
+ // If you set this higher than the overall timeout, you'll get an error when you
+ // try to run the expression.
+ void
+ SetOneThreadTimeoutInMicroSeconds (uint32_t timeout = 0);
+
bool
GetTryAllThreads () const;
void
SetTryAllThreads (bool run_others = true);
+
+ bool
+ GetStopOthers() const;
+
+ void
+ SetStopOthers(bool stop_others = true);
bool
GetTrapExceptions () const;
void
SetTrapExceptions (bool trap_exceptions = true);
+
+ void
+ SetLanguage (lldb::LanguageType language);
+
+ void
+ SetCancelCallback (lldb::ExpressionCancelCallback callback, void *baton);
+
+ bool
+ GetGenerateDebugInfo ();
+
+ void
+ SetGenerateDebugInfo (bool b = true);
+
+ bool
+ GetSuppressPersistentResult ();
+
+ void
+ SetSuppressPersistentResult (bool b = false);
protected:
diff --git a/include/lldb/API/SBFileSpec.h b/include/lldb/API/SBFileSpec.h
index 5d4447f74e64..d262b98d0fd7 100644
--- a/include/lldb/API/SBFileSpec.h
+++ b/include/lldb/API/SBFileSpec.h
@@ -21,7 +21,7 @@ public:
SBFileSpec (const lldb::SBFileSpec &rhs);
- SBFileSpec (const char *path);// Deprected, use SBFileSpec (const char *path, bool resolve)
+ SBFileSpec (const char *path);// Deprecated, use SBFileSpec (const char *path, bool resolve)
SBFileSpec (const char *path, bool resolve);
diff --git a/include/lldb/API/SBFrame.h b/include/lldb/API/SBFrame.h
index 4ae38c13bede..f6b84ab1ddac 100644
--- a/include/lldb/API/SBFrame.h
+++ b/include/lldb/API/SBFrame.h
@@ -75,7 +75,7 @@ public:
/// Get the appropriate function name for this frame. Inlined functions in
/// LLDB are represented by Blocks that have inlined function information, so
/// just looking at the SBFunction or SBSymbol for a frame isn't enough.
- /// This function will return the appriopriate function, symbol or inlined
+ /// This function will return the appropriate function, symbol or inlined
/// function name for the frame.
///
/// This function returns:
diff --git a/include/lldb/API/SBHostOS.h b/include/lldb/API/SBHostOS.h
index e5fab6fe7849..7ab22caaaad9 100644
--- a/include/lldb/API/SBHostOS.h
+++ b/include/lldb/API/SBHostOS.h
@@ -25,12 +25,15 @@ public:
static lldb::SBFileSpec
GetLLDBPythonPath ();
+ static lldb::SBFileSpec
+ GetLLDBPath (lldb::PathType path_type);
+
static void
ThreadCreated (const char *name);
static lldb::thread_t
ThreadCreate (const char *name,
- thread_func_t thread_function,
+ lldb::thread_func_t thread_function,
void *thread_arg,
lldb::SBError *err);
@@ -43,7 +46,7 @@ public:
lldb::SBError *err);
static bool
ThreadJoin (lldb::thread_t thread,
- thread_result_t *result,
+ lldb::thread_result_t *result,
lldb::SBError *err);
diff --git a/include/lldb/API/SBListener.h b/include/lldb/API/SBListener.h
index c5a047341741..4a11ec1072f1 100644
--- a/include/lldb/API/SBListener.h
+++ b/include/lldb/API/SBListener.h
@@ -55,7 +55,7 @@ public:
StopListeningForEvents (const lldb::SBBroadcaster& broadcaster,
uint32_t event_mask);
- // Returns true if an event was recieved, false if we timed out.
+ // Returns true if an event was received, false if we timed out.
bool
WaitForEvent (uint32_t num_seconds,
lldb::SBEvent &event);
diff --git a/include/lldb/API/SBProcess.h b/include/lldb/API/SBProcess.h
index f2846710c614..4b59462ca3f1 100644
--- a/include/lldb/API/SBProcess.h
+++ b/include/lldb/API/SBProcess.h
@@ -221,6 +221,9 @@ public:
lldb::SBError
Signal (int signal);
+ lldb::SBUnixSignals
+ GetUnixSignals();
+
void
SendAsyncInterrupt();
@@ -279,6 +282,9 @@ public:
lldb::SBError
UnloadImage (uint32_t image_token);
+ lldb::SBError
+ SendEventData (const char *data);
+
//------------------------------------------------------------------
/// Return the number of different thread-origin extended backtraces
/// this process can support.
diff --git a/include/lldb/API/SBQueue.h b/include/lldb/API/SBQueue.h
index 6ab9aa09f466..fbb1952902f8 100644
--- a/include/lldb/API/SBQueue.h
+++ b/include/lldb/API/SBQueue.h
@@ -14,7 +14,6 @@
#include "lldb/lldb-forward.h"
#include "lldb/API/SBDefines.h"
-#include "lldb/API/SBQueueItem.h"
namespace lldb {
@@ -62,8 +61,15 @@ public:
lldb::SBQueueItem
GetPendingItemAtIndex (uint32_t);
+ uint32_t
+ GetNumRunningItems ();
+
+ lldb::QueueKind
+ GetKind ();
+
protected:
friend class SBProcess;
+ friend class SBThread;
void
SetQueue (const lldb::QueueSP& queue_sp);
diff --git a/include/lldb/API/SBQueueItem.h b/include/lldb/API/SBQueueItem.h
index 355c5ac90a23..c90f36eeb573 100644
--- a/include/lldb/API/SBQueueItem.h
+++ b/include/lldb/API/SBQueueItem.h
@@ -12,7 +12,6 @@
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBAddress.h"
-#include "lldb/API/SBThread.h"
namespace lldb {
diff --git a/include/lldb/API/SBStream.h b/include/lldb/API/SBStream.h
index 038adf68542c..fb69c12f0a91 100644
--- a/include/lldb/API/SBStream.h
+++ b/include/lldb/API/SBStream.h
@@ -51,7 +51,7 @@ public:
RedirectToFileDescriptor (int fd, bool transfer_fh_ownership);
// If the stream is redirected to a file, forget about the file and if
- // ownership of the file was transfered to this object, close the file.
+ // ownership of the file was transferred to this object, close the file.
// If the stream is backed by a local cache, clear this cache.
void
Clear ();
@@ -86,6 +86,7 @@ protected:
friend class SBTarget;
friend class SBThread;
friend class SBType;
+ friend class SBTypeEnumMember;
friend class SBTypeMember;
friend class SBValue;
friend class SBWatchpoint;
diff --git a/include/lldb/API/SBTarget.h b/include/lldb/API/SBTarget.h
index 230dffc68251..370d40d0454a 100644
--- a/include/lldb/API/SBTarget.h
+++ b/include/lldb/API/SBTarget.h
@@ -47,6 +47,35 @@ public:
void
SetGroupID (uint32_t gid);
+ SBFileSpec
+ GetExecutableFile ();
+
+ //----------------------------------------------------------------------
+ /// Set the executable file that will be used to launch the process and
+ /// optionally set it as the first argument in the argument vector.
+ ///
+ /// This only needs to be specified if clients wish to carefully control
+ /// the exact path will be used to launch a binary. If you create a
+ /// target with a symlink, that symlink will get resolved in the target
+ /// and the resolved path will get used to launch the process. Calling
+ /// this function can help you still launch your process using the
+ /// path of your choice.
+ ///
+ /// If this function is not called prior to launching with
+ /// SBTarget::Launch(...), the target will use the resolved executable
+ /// path that was used to create the target.
+ ///
+ /// @param[in] exe_file
+ /// The override path to use when launching the executable.
+ ///
+ /// @param[in] add_as_first_arg
+ /// If true, then the path will be inserted into the argument vector
+ /// prior to launching. Otherwise the argument vector will be left
+ /// alone.
+ //----------------------------------------------------------------------
+ void
+ SetExecutableFile (SBFileSpec exe_file, bool add_as_first_arg);
+
uint32_t
GetNumArguments ();
@@ -110,6 +139,18 @@ public:
bool
AddSuppressFileAction (int fd, bool read, bool write);
+ void
+ SetLaunchEventData (const char *data);
+
+ const char *
+ GetLaunchEventData () const;
+
+ bool
+ GetDetachOnError() const;
+
+ void
+ SetDetachOnError(bool enable);
+
protected:
friend class SBTarget;
@@ -331,7 +372,7 @@ public:
/// Some launch options specified by logical OR'ing
/// lldb::LaunchFlags enumeration values together.
///
- /// @param[in] stop_at_endtry
+ /// @param[in] stop_at_entry
/// If false do not stop the inferior at the entry point.
///
/// @param[out]
@@ -580,7 +621,7 @@ public:
//------------------------------------------------------------------
- /// The the section base load addresses for all sections in a module.
+ /// Clear the section base load addresses for all sections in a module.
///
/// @param[in] module
/// The module to unload.
diff --git a/include/lldb/API/SBThread.h b/include/lldb/API/SBThread.h
index 04b6c86e6d89..07a43ebee7ce 100644
--- a/include/lldb/API/SBThread.h
+++ b/include/lldb/API/SBThread.h
@@ -41,6 +41,9 @@ public:
~SBThread();
+ lldb::SBQueue
+ GetQueue () const;
+
bool
IsValid() const;
@@ -97,6 +100,9 @@ public:
lldb::queue_id_t
GetQueueID() const;
+ bool
+ GetInfoItemByPathAsString ( const char *path, SBStream &strm);
+
void
StepOver (lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping);
@@ -136,8 +142,8 @@ public:
/// the other threads in a process are allowed to run. So when
/// SBProcess::Continue() is called, any threads that aren't suspended will
/// be allowed to run. If any of the SBThread functions for stepping are
- /// called (StepOver, StepInto, StepOut, StepInstruction, RunToAddres), the
- /// thread will not be allowed to run and these funtions will simply return.
+ /// called (StepOver, StepInto, StepOut, StepInstruction, RunToAddress), the
+ /// thread will not be allowed to run and these functions will simply return.
///
/// Eventually we plan to add support for thread centric debugging where
/// each thread is controlled individually and each thread would broadcast
@@ -207,6 +213,9 @@ public:
uint32_t
GetExtendedBacktraceOriginatingIndexID ();
+ bool
+ SafeToCallFunctions ();
+
protected:
friend class SBBreakpoint;
friend class SBBreakpointLocation;
diff --git a/include/lldb/API/SBType.h b/include/lldb/API/SBType.h
index 2cd9b4459a33..363aa59e35aa 100644
--- a/include/lldb/API/SBType.h
+++ b/include/lldb/API/SBType.h
@@ -143,6 +143,9 @@ public:
lldb::SBTypeMember
GetVirtualBaseClassAtIndex (uint32_t idx);
+ lldb::SBTypeEnumMemberList
+ GetEnumMembers();
+
uint32_t
GetNumberOfTemplateArguments ();
@@ -161,6 +164,9 @@ public:
const char*
GetName();
+ const char *
+ GetDisplayTypeName ();
+
lldb::TypeClass
GetTypeClass ();
@@ -199,6 +205,8 @@ protected:
friend class SBFunction;
friend class SBModule;
friend class SBTarget;
+ friend class SBTypeEnumMember;
+ friend class SBTypeEnumMemberList;
friend class SBTypeNameSpecifier;
friend class SBTypeMember;
friend class SBTypeList;
diff --git a/include/lldb/API/SBTypeEnumMember.h b/include/lldb/API/SBTypeEnumMember.h
new file mode 100644
index 000000000000..75c9917989c2
--- /dev/null
+++ b/include/lldb/API/SBTypeEnumMember.h
@@ -0,0 +1,98 @@
+
+//===-- SBTypeEnumMember.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBTypeEnumMember_h_
+#define LLDB_SBTypeEnumMember_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBTypeEnumMember
+{
+public:
+ SBTypeEnumMember ();
+
+ SBTypeEnumMember (const SBTypeEnumMember& rhs);
+
+ ~SBTypeEnumMember();
+
+ SBTypeEnumMember&
+ operator = (const SBTypeEnumMember& rhs);
+
+ bool
+ IsValid() const;
+
+ int64_t
+ GetValueAsSigned();
+
+ uint64_t
+ GetValueAsUnsigned();
+
+ const char *
+ GetName ();
+
+ lldb::SBType
+ GetType ();
+
+ bool
+ GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level);
+
+protected:
+ friend class SBType;
+ friend class SBTypeEnumMemberList;
+
+ void
+ reset (lldb_private::TypeEnumMemberImpl *);
+
+ lldb_private::TypeEnumMemberImpl &
+ ref ();
+
+ const lldb_private::TypeEnumMemberImpl &
+ ref () const;
+
+ lldb::TypeEnumMemberImplSP m_opaque_sp;
+
+ SBTypeEnumMember (const lldb::TypeEnumMemberImplSP &);
+};
+
+class SBTypeEnumMemberList
+{
+public:
+ SBTypeEnumMemberList();
+
+ SBTypeEnumMemberList(const SBTypeEnumMemberList& rhs);
+
+ ~SBTypeEnumMemberList();
+
+ SBTypeEnumMemberList&
+ operator = (const SBTypeEnumMemberList& rhs);
+
+ bool
+ IsValid();
+
+ void
+ Append (SBTypeEnumMember entry);
+
+ SBTypeEnumMember
+ GetTypeEnumMemberAtIndex (uint32_t index);
+
+ uint32_t
+ GetSize();
+
+
+private:
+ std::unique_ptr<lldb_private::TypeEnumMemberListImpl> m_opaque_ap;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBTypeEnumMember_h_
diff --git a/include/lldb/API/SBUnixSignals.h b/include/lldb/API/SBUnixSignals.h
new file mode 100644
index 000000000000..40bbed8b48ef
--- /dev/null
+++ b/include/lldb/API/SBUnixSignals.h
@@ -0,0 +1,84 @@
+//===-- SBUnixSignals.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBUnixSignals_h_
+#define LLDB_SBUnixSignals_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBUnixSignals {
+public:
+ SBUnixSignals ();
+
+ SBUnixSignals (const lldb::SBUnixSignals &rhs);
+
+ ~SBUnixSignals();
+
+ const SBUnixSignals &
+ operator =(const lldb::SBUnixSignals &rhs);
+
+ void
+ Clear ();
+
+ bool
+ IsValid () const;
+
+ const char *
+ GetSignalAsCString (int32_t signo) const;
+
+ int32_t
+ GetSignalNumberFromName (const char *name) const;
+
+ bool
+ GetShouldSuppress (int32_t signo) const;
+
+ bool
+ SetShouldSuppress (int32_t signo,
+ bool value);
+
+ bool
+ GetShouldStop (int32_t signo) const;
+
+ bool
+ SetShouldStop (int32_t signo,
+ bool value);
+
+ bool
+ GetShouldNotify (int32_t signo) const;
+
+ bool
+ SetShouldNotify (int32_t signo, bool value);
+
+ int32_t
+ GetNumSignals () const;
+
+ int32_t
+ GetSignalAtIndex (int32_t index) const;
+
+protected:
+ friend class SBProcess;
+
+ SBUnixSignals (lldb::ProcessSP &process_sp);
+
+ lldb::ProcessSP
+ GetSP() const;
+
+ void
+ SetSP (const lldb::ProcessSP &process_sp);
+
+private:
+ lldb::ProcessWP m_opaque_wp;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBUnixSignals_h_
diff --git a/include/lldb/API/SBValue.h b/include/lldb/API/SBValue.h
index 2b9a344b9300..93b869ba9c5c 100644
--- a/include/lldb/API/SBValue.h
+++ b/include/lldb/API/SBValue.h
@@ -50,6 +50,9 @@ public:
const char *
GetTypeName ();
+
+ const char *
+ GetDisplayTypeName ();
size_t
GetByteSize ();
@@ -173,7 +176,7 @@ public:
//------------------------------------------------------------------
/// Get a child value by index from a value.
///
- /// Structs, unions, classes, arrays and and pointers have child
+ /// Structs, unions, classes, arrays and pointers have child
/// values that can be access by index.
///
/// Structs and unions access child members using a zero based index
@@ -208,7 +211,7 @@ public:
/// The index of the child value to get
///
/// @param[in] use_dynamic
- /// An enumeration that specifies wether to get dynamic values,
+ /// An enumeration that specifies whether to get dynamic values,
/// and also if the target can be run to figure out the dynamic
/// type of the child value.
///
diff --git a/include/lldb/Breakpoint/Breakpoint.h b/include/lldb/Breakpoint/Breakpoint.h
index 749ff8d1a09c..15693f86e382 100644
--- a/include/lldb/Breakpoint/Breakpoint.h
+++ b/include/lldb/Breakpoint/Breakpoint.h
@@ -431,7 +431,7 @@ public:
/// @param[in] is_synchronous
/// If \b true the callback will be run on the private event thread
/// before the stop event gets reported. If false, the callback will get
- /// handled on the public event thead after the stop has been posted.
+ /// handled on the public event thread after the stop has been posted.
///
/// @return
/// \b true if the process should stop when you hit the breakpoint.
diff --git a/include/lldb/Breakpoint/BreakpointLocationList.h b/include/lldb/Breakpoint/BreakpointLocationList.h
index ec34641b727c..0d8062eb644c 100644
--- a/include/lldb/Breakpoint/BreakpointLocationList.h
+++ b/include/lldb/Breakpoint/BreakpointLocationList.h
@@ -143,7 +143,7 @@ public:
ClearAllBreakpointSites ();
//------------------------------------------------------------------
- /// Tells all the breakopint locations in this list to attempt to
+ /// Tells all the breakpoint locations in this list to attempt to
/// resolve any possible breakpoint sites.
//------------------------------------------------------------------
void
diff --git a/include/lldb/Breakpoint/BreakpointOptions.h b/include/lldb/Breakpoint/BreakpointOptions.h
index 728f5932fa06..eb374ad69603 100644
--- a/include/lldb/Breakpoint/BreakpointOptions.h
+++ b/include/lldb/Breakpoint/BreakpointOptions.h
@@ -145,7 +145,8 @@ public:
/// @return
/// The synchronicity of our callback.
//------------------------------------------------------------------
- bool IsCallbackSynchronous () {
+ bool IsCallbackSynchronous () const
+ {
return m_callback_is_synchronous;
}
@@ -280,7 +281,7 @@ public:
/// Returns true if the breakpoint option has a callback set.
//------------------------------------------------------------------
bool
- HasCallback();
+ HasCallback() const;
//------------------------------------------------------------------
/// This is the default empty callback.
diff --git a/include/lldb/Breakpoint/BreakpointSite.h b/include/lldb/Breakpoint/BreakpointSite.h
index 271a23c2e451..1d2cbea18f9f 100644
--- a/include/lldb/Breakpoint/BreakpointSite.h
+++ b/include/lldb/Breakpoint/BreakpointSite.h
@@ -19,6 +19,7 @@
// Project includes
#include "lldb/lldb-private.h"
+#include "lldb/Host/Mutex.h"
#include "lldb/Core/UserID.h"
#include "lldb/Breakpoint/StoppointLocation.h"
#include "lldb/Breakpoint/BreakpointLocationCollection.h"
@@ -33,7 +34,7 @@ namespace lldb_private {
/// The BreakpointSite class handles the physical breakpoint that is
/// actually inserted in the target program. As such, it is also the
/// one that gets hit, when the program stops. It keeps a list of all
-/// BreakpointLocations that share this phsyical site. When the
+/// BreakpointLocations that share this physical site. When the
/// breakpoint is hit, all the locations are informed by the breakpoint
/// site. Breakpoint sites are owned by the process.
//----------------------------------------------------------------------
@@ -50,7 +51,7 @@ public:
// and m_trap_opcode contain the saved and written opcode.
eHardware, // Breakpoint site is set as a hardware breakpoint
eExternal // Breakpoint site is managed by an external debug nub or
- // debug interface where memory reads trasparently will not
+ // debug interface where memory reads transparently will not
// display any breakpoint opcodes.
};
@@ -123,7 +124,7 @@ public:
/// Sets whether the current breakpoint site is enabled or not
///
/// @param[in] enabled
- /// \b true if the breakoint is enabled, \b false otherwise.
+ /// \b true if the breakpoint is enabled, \b false otherwise.
//------------------------------------------------------------------
void
SetEnabled (bool enabled);
@@ -172,7 +173,7 @@ public:
GetNumberOfOwners ();
//------------------------------------------------------------------
- /// This method returns the the breakpoint location at index \a index
+ /// This method returns the breakpoint location at index \a index
/// located at this breakpoint site. The owners are listed ordinally
/// from 0 to GetNumberOfOwners() - 1 so you can use this method to iterate
/// over the owners
@@ -257,6 +258,7 @@ public:
private:
friend class Process;
+ friend class BreakpointLocation;
//------------------------------------------------------------------
/// The method removes the owner at \a break_loc_id from this breakpoint list.
@@ -276,6 +278,7 @@ private:
// Consider adding an optimization where if there is only one
// owner, we don't store a list. The usual case will be only one owner...
BreakpointLocationCollection m_owners; ///< This has the BreakpointLocations that share this breakpoint site.
+ Mutex m_owners_mutex; ///< This mutex protects the owners collection.
static lldb::break_id_t
GetNextID();
diff --git a/include/lldb/Breakpoint/Watchpoint.h b/include/lldb/Breakpoint/Watchpoint.h
index 5dbed03d5406..8493775eec34 100644
--- a/include/lldb/Breakpoint/Watchpoint.h
+++ b/include/lldb/Breakpoint/Watchpoint.h
@@ -134,7 +134,7 @@ public:
/// @param[in] is_synchronous
/// If \b true the callback will be run on the private event thread
/// before the stop event gets reported. If false, the callback will get
- /// handled on the public event thead after the stop has been posted.
+ /// handled on the public event thread after the stop has been posted.
///
/// @return
/// \b true if the process should stop when you hit the watchpoint.
@@ -215,7 +215,7 @@ private:
// undergoing a pair of temporary disable/enable actions to avoid recursively
// triggering further watchpoint events.
uint32_t m_disabled_count; // Keep track of the count that the watchpoint is disabled while in ephemeral mode.
- // At the end of the ephemeral mode when the watchpoint is to be enabled agian,
+ // At the end of the ephemeral mode when the watchpoint is to be enabled again,
// we check the count, if it is more than 1, it means the user-supplied actions
// actually want the watchpoint to be disabled!
uint32_t m_watch_read:1, // 1 if we stop when the watched data is read from
diff --git a/include/lldb/Core/Address.h b/include/lldb/Core/Address.h
index 322019395ae7..8dd2339f9207 100644
--- a/include/lldb/Core/Address.h
+++ b/include/lldb/Core/Address.h
@@ -230,7 +230,7 @@ public:
/// offset based address, and \a style lets the user choose.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
///
/// @param[in] style
/// The display style for the address.
@@ -310,7 +310,7 @@ public:
///
/// This function will first resolve its address to a load address.
/// Then, if the address turns out to be in code address, return the
- /// load address for a an opcode. This address object might have
+ /// load address for an opcode. This address object might have
/// extra bits set (bit zero will be set to Thumb functions for an
/// ARM target) that are required for changing the program counter
/// and this function will remove any bits that are intended for
@@ -362,7 +362,7 @@ public:
/// offset (for absolute addresses that have no section).
///
/// @return
- /// Returns \b true if the the offset is valid, \b false
+ /// Returns \b true if the offset is valid, \b false
/// otherwise.
//------------------------------------------------------------------
bool
diff --git a/include/lldb/Core/AddressRange.h b/include/lldb/Core/AddressRange.h
index bd3ab2ab5da5..9d781f3e85ae 100644
--- a/include/lldb/Core/AddressRange.h
+++ b/include/lldb/Core/AddressRange.h
@@ -189,7 +189,7 @@ public:
/// how the base address gets displayed.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
///
/// @param[in] style
/// The display style for the address.
@@ -215,7 +215,7 @@ public:
/// and pointer values, reference counts, etc.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
//------------------------------------------------------------------
void
DumpDebug (Stream *s) const;
diff --git a/include/lldb/Core/ArchSpec.h b/include/lldb/Core/ArchSpec.h
index 1ccb385783a0..255beee573b6 100644
--- a/include/lldb/Core/ArchSpec.h
+++ b/include/lldb/Core/ArchSpec.h
@@ -50,6 +50,7 @@ public:
eCore_arm_armv7m,
eCore_arm_armv7em,
eCore_arm_xscale,
+
eCore_thumb,
eCore_thumbv4t,
eCore_thumbv5,
@@ -57,11 +58,14 @@ public:
eCore_thumbv6,
eCore_thumbv6m,
eCore_thumbv7,
- eCore_thumbv7f,
eCore_thumbv7s,
eCore_thumbv7k,
+ eCore_thumbv7f,
eCore_thumbv7m,
eCore_thumbv7em,
+ eCore_arm_arm64,
+ eCore_arm_armv8,
+ eCore_arm_aarch64,
eCore_mips64,
@@ -89,6 +93,7 @@ public:
eCore_x86_32_i386,
eCore_x86_32_i486,
eCore_x86_32_i486sx,
+ eCore_x86_32_i686,
eCore_x86_64_x86_64,
eCore_x86_64_x86_64h, // Haswell enabled x86_64
@@ -98,6 +103,12 @@ public:
eCore_uknownMach32,
eCore_uknownMach64,
+
+ eCore_kalimba,
+ eCore_kalimba3,
+ eCore_kalimba4,
+ eCore_kalimba5,
+
kNumCores,
kCore_invalid,
@@ -107,6 +118,7 @@ public:
kCore_ppc_any,
kCore_ppc64_any,
kCore_x86_32_any,
+ kCore_x86_64_any,
kCore_hexagon_any,
kCore_arm_first = eCore_arm_generic,
@@ -122,10 +134,16 @@ public:
kCore_ppc64_last = eCore_ppc64_ppc970_64,
kCore_x86_32_first = eCore_x86_32_i386,
- kCore_x86_32_last = eCore_x86_32_i486sx,
+ kCore_x86_32_last = eCore_x86_32_i686,
+
+ kCore_x86_64_first = eCore_x86_64_x86_64,
+ kCore_x86_64_last = eCore_x86_64_x86_64h,
kCore_hexagon_first = eCore_hexagon_generic,
- kCore_hexagon_last = eCore_hexagon_hexagonv5
+ kCore_hexagon_last = eCore_hexagon_hexagonv5,
+
+ kCore_kalimba_first = eCore_kalimba,
+ kCore_kalimba_last = eCore_kalimba5
};
//------------------------------------------------------------------
@@ -228,7 +246,7 @@ public:
///
/// This will be something like "ubuntu", "fedora", etc. on Linux.
/// This should be the same value returned by
- /// Host::GetDistributionId ().
+ /// HostInfo::GetDistributionId ().
///------------------------------------------------------------------
void
SetDistributionId (const char* distribution_id);
@@ -302,7 +320,7 @@ public:
///
/// @param[in] cpu The required CPU type.
///
- /// @return True if the object and CPU type were sucessfully set.
+ /// @return True if the object and CPU type were successfully set.
//------------------------------------------------------------------
bool
SetArchitecture (ArchitectureType arch_type,
@@ -351,6 +369,24 @@ public:
GetMachOCPUSubType () const;
//------------------------------------------------------------------
+ /// Architecture data byte width accessor
+ ///
+ /// @return the size in 8-bit (host) bytes of a minimum addressable
+ /// unit from the Architecture's data bus
+ //------------------------------------------------------------------
+ uint32_t
+ GetDataByteSize() const;
+
+ //------------------------------------------------------------------
+ /// Architecture code byte width accessor
+ ///
+ /// @return the size in 8-bit (host) bytes of a minimum addressable
+ /// unit from the Architecture's code bus
+ //------------------------------------------------------------------
+ uint32_t
+ GetCodeByteSize() const;
+
+ //------------------------------------------------------------------
/// Architecture tripple accessor.
///
/// @return A triple describing this ArchSpec.
diff --git a/include/lldb/Core/ClangForward.h b/include/lldb/Core/ClangForward.h
index 0b3f13a16602..ef7308d25f7f 100644
--- a/include/lldb/Core/ClangForward.h
+++ b/include/lldb/Core/ClangForward.h
@@ -58,6 +58,7 @@ namespace clang
class DiagnosticsEngine;
class DiagnosticOptions;
class EnumDecl;
+ class EnumConstantDecl;
class Expr;
class ExternalASTSource;
class ExtVectorElementExpr;
diff --git a/include/lldb/Core/Communication.h b/include/lldb/Core/Communication.h
index 2dde55044171..7e8209d7d9c6 100644
--- a/include/lldb/Core/Communication.h
+++ b/include/lldb/Core/Communication.h
@@ -59,7 +59,7 @@ namespace lldb_private {
///
/// bool Communication::StartReadThread (Error *);
///
-/// If true is returned a read thead has been spawned that will
+/// If true is returned a read thread has been spawned that will
/// continually execute a call to the pure virtual DoRead function:
///
/// size_t Communication::ReadFromConnection (void *, size_t, uint32_t);
@@ -300,7 +300,7 @@ public:
//------------------------------------------------------------------
/// The static read thread function. This function will call
/// the "DoRead" function continuously and wait for data to become
- /// avaialble. When data is received it will append the available
+ /// available. When data is received it will append the available
/// data to the internal cache and broadcast a
/// \b eBroadcastBitReadThreadGotBytes event.
///
diff --git a/include/lldb/Core/ConnectionFileDescriptor.h b/include/lldb/Core/ConnectionFileDescriptor.h
index 15598c9b1335..75d0202fcf6c 100644
--- a/include/lldb/Core/ConnectionFileDescriptor.h
+++ b/include/lldb/Core/ConnectionFileDescriptor.h
@@ -10,24 +10,23 @@
#ifndef liblldb_ConnectionFileDescriptor_h_
#define liblldb_ConnectionFileDescriptor_h_
-// C Includes
-#ifndef _WIN32
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#endif
-
// C++ Includes
#include <memory>
+#include "lldb/lldb-forward.h"
+
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Connection.h"
#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Pipe.h"
#include "lldb/Host/Predicate.h"
+#include "lldb/Host/IOObject.h"
namespace lldb_private {
+class Error;
+class Socket;
class SocketAddress;
class ConnectionFileDescriptor :
@@ -64,81 +63,52 @@ public:
lldb::ConnectionStatus &status,
Error *error_ptr);
- // If the read file descriptor is a socket, then return
- // the port number that is being used by the socket.
- uint16_t
- GetReadPort () const;
-
- // If the write file descriptor is a socket, then return
- // the port number that is being used by the socket.
- uint16_t
- GetWritePort () const;
+ lldb::ConnectionStatus
+ BytesAvailable (uint32_t timeout_usec, Error *error_ptr);
- uint16_t
- GetBoundPort (uint32_t timeout_sec);
+ bool
+ InterruptRead ();
-protected:
+ lldb::IOObjectSP GetReadObject() { return m_read_sp; }
+ const lldb::IOObjectSP GetReadObject() const { return m_read_sp; }
- typedef enum
- {
- eFDTypeFile, // Other FD requireing read/write
- eFDTypeSocket, // Socket requiring send/recv
- eFDTypeSocketUDP // Unconnected UDP socket requiring sendto/recvfrom
- } FDType;
+ uint16_t GetListeningPort(uint32_t timeout_sec);
+
+protected:
void
OpenCommandPipe ();
void
CloseCommandPipe ();
-
- lldb::ConnectionStatus
- BytesAvailable (uint32_t timeout_usec, Error *error_ptr);
lldb::ConnectionStatus
SocketListen (const char *host_and_port, Error *error_ptr);
-
+
lldb::ConnectionStatus
ConnectTCP (const char *host_and_port, Error *error_ptr);
-
+
lldb::ConnectionStatus
ConnectUDP (const char *args, Error *error_ptr);
lldb::ConnectionStatus
- NamedSocketAccept (const char *socket_name, Error *error_ptr);
-
- lldb::ConnectionStatus
NamedSocketConnect (const char *socket_name, Error *error_ptr);
-
+
lldb::ConnectionStatus
- Close (int& fd, FDType type, Error *error);
-
- int m_fd_send;
- int m_fd_recv;
- FDType m_fd_send_type;
- FDType m_fd_recv_type;
- std::unique_ptr<SocketAddress> m_udp_send_sockaddr;
- uint32_t m_socket_timeout_usec;
- int m_pipe_read; // A pipe that we select on the reading end of along with
- int m_pipe_write; // m_fd_recv so we can force ourselves out of the select.
- Mutex m_mutex;
- Predicate<uint16_t> m_port_predicate; // Used when binding to port zero to wait for the thread that creates the socket, binds and listens to resolve the port number
- bool m_should_close_fd; // True if this class should close the file descriptor when it goes away.
- bool m_shutting_down; // This marks that we are shutting down so if we get woken up from BytesAvailable
- // to disconnect, we won't try to read again.
+ NamedSocketAccept (const char *socket_name, Error *error_ptr);
- static uint16_t
- GetSocketPort (int fd);
-
- static int
- GetSocketOption(int fd, int level, int option_name, int &option_value);
+ lldb::IOObjectSP m_read_sp;
+ lldb::IOObjectSP m_write_sp;
- static int
- SetSocketOption(int fd, int level, int option_name, int option_value);
-
- bool
- SetSocketReceiveTimeout (uint32_t timeout_usec);
+ Predicate<uint16_t> m_port_predicate; // Used when binding to port zero to wait for the thread
+ // that creates the socket, binds and listens to resolve
+ // the port number.
+ Pipe m_pipe;
+ Mutex m_mutex;
+ bool m_shutting_down; // This marks that we are shutting down so if we get woken up from
+ // BytesAvailable to disconnect, we won't try to read again.
+ bool m_waiting_for_accept;
private:
DISALLOW_COPY_AND_ASSIGN (ConnectionFileDescriptor);
};
diff --git a/include/lldb/Core/ConstString.h b/include/lldb/Core/ConstString.h
index 684cc8f921ed..cfa237c46862 100644
--- a/include/lldb/Core/ConstString.h
+++ b/include/lldb/Core/ConstString.h
@@ -303,7 +303,7 @@ public:
/// returns an integer result.
///
/// NOTE: only call this function when you want a true string
- /// comparision. If you want string equality use the, use the ==
+ /// comparison. If you want string equality use the, use the ==
/// operator as it is much more efficient. Also if you want string
/// inequality, use the != operator for the same reasons.
///
@@ -383,7 +383,7 @@ public:
//------------------------------------------------------------------
/// Set the C string value and its mangled counterpart.
///
- /// Object files and debug sybmols often use mangled string to
+ /// Object files and debug symbols often use mangled string to
/// represent the linkage name for a symbol, function or global.
/// The string pool can efficiently store these values and their
/// counterparts so when we run into another instance of a mangled
@@ -406,7 +406,7 @@ public:
/// Retrieve the mangled or demangled counterpart for a mangled
/// or demangled ConstString.
///
- /// Object files and debug sybmols often use mangled string to
+ /// Object files and debug symbols often use mangled string to
/// represent the linkage name for a symbol, function or global.
/// The string pool can efficiently store these values and their
/// counterparts so when we run into another instance of a mangled
@@ -478,7 +478,7 @@ public:
//------------------------------------------------------------------
/// Get the size in bytes of the current global string pool.
///
- /// Reports the the size in bytes of all shared C string values,
+ /// Reports the size in bytes of all shared C string values,
/// containers and any other values as a byte size for the
/// entire string pool.
///
diff --git a/include/lldb/Core/DataBuffer.h b/include/lldb/Core/DataBuffer.h
index e64245dead3d..64e2a8857837 100644
--- a/include/lldb/Core/DataBuffer.h
+++ b/include/lldb/Core/DataBuffer.h
@@ -20,7 +20,7 @@ namespace lldb_private {
/// @class DataBuffer DataBuffer.h "lldb/Core/DataBuffer.h"
/// @brief A pure virtual protocol class for abstracted data buffers.
///
-/// DataBuffer is an abtract class that gets packaged into a shared pointer
+/// DataBuffer is an abstract class that gets packaged into a shared pointer
/// that can use to implement various ways to store data (on the heap,
/// memory mapped, cached inferior memory). It gets used by DataExtractor
/// so many DataExtractor objects can share the same data and sub-ranges
diff --git a/include/lldb/Core/DataBufferHeap.h b/include/lldb/Core/DataBufferHeap.h
index dac9a28befb9..ad73fabe5f1e 100644
--- a/include/lldb/Core/DataBufferHeap.h
+++ b/include/lldb/Core/DataBufferHeap.h
@@ -122,6 +122,9 @@ public:
CopyData (const void *src, lldb::offset_t src_len);
void
+ AppendData (const void *src, uint64_t src_len);
+
+ void
Clear();
private:
diff --git a/include/lldb/Core/DataBufferMemoryMap.h b/include/lldb/Core/DataBufferMemoryMap.h
index d4a448a5df52..944b975a318a 100644
--- a/include/lldb/Core/DataBufferMemoryMap.h
+++ b/include/lldb/Core/DataBufferMemoryMap.h
@@ -100,7 +100,12 @@ public:
/// @param[in] length
/// The size in bytes that should be mapped starting \a offset
/// bytes into the file. If \a length is \c SIZE_MAX, map
- /// as many bytes as possible.
+ /// as many bytes as possible. Even though it may be possible
+ /// for a 32-bit host debugger to debug a 64-bit target, size_t
+ /// still dictates the maximum possible size that can be mapped
+ /// into this process. For this kind of cross-arch debugging
+ /// scenario, mappings and views should be managed at a higher
+ /// level.
///
/// @return
/// The number of bytes mapped starting from the \a offset.
@@ -108,7 +113,7 @@ public:
size_t
MemoryMapFromFileSpec (const FileSpec* file,
lldb::offset_t offset = 0,
- lldb::offset_t length = SIZE_MAX,
+ size_t length = SIZE_MAX,
bool writeable = false);
//------------------------------------------------------------------
@@ -137,7 +142,7 @@ public:
size_t
MemoryMapFromFileDescriptor (int fd,
lldb::offset_t offset,
- lldb::offset_t length,
+ size_t length,
bool write,
bool fd_is_file);
diff --git a/include/lldb/Core/DataEncoder.h b/include/lldb/Core/DataEncoder.h
index 658cce0d2b4b..7cd5d6808152 100644
--- a/include/lldb/Core/DataEncoder.h
+++ b/include/lldb/Core/DataEncoder.h
@@ -173,7 +173,7 @@ public:
}
//------------------------------------------------------------------
- /// Get a the data start pointer.
+ /// Get the data start pointer.
///
/// @return
/// Returns a pointer to the first byte contained in this
@@ -234,7 +234,7 @@ public:
/// The size in byte of the integer to encode.
///
/// @param[in] value
- /// The integer value to write. The least significate bytes of
+ /// The integer value to write. The least significant bytes of
/// the integer value will be written if the size is less than
/// 8 bytes.
///
@@ -253,7 +253,7 @@ public:
/// start encoding.
///
/// @param[int] src
- /// The buffer that contains the the bytes to encode.
+ /// The buffer that contains the bytes to encode.
///
/// @param[in] src_len
/// The number of bytes to encode.
diff --git a/include/lldb/Core/Debugger.h b/include/lldb/Core/Debugger.h
index e80ec8516793..7ab62e5b7f3a 100644
--- a/include/lldb/Core/Debugger.h
+++ b/include/lldb/Core/Debugger.h
@@ -31,6 +31,14 @@
#include "lldb/Target/Platform.h"
#include "lldb/Target/TargetList.h"
+namespace llvm
+{
+namespace sys
+{
+class DynamicLibrary;
+}
+}
+
namespace lldb_private {
//----------------------------------------------------------------------
@@ -51,9 +59,9 @@ friend class SourceManager; // For GetSourceFileCache.
public:
- typedef lldb::DynamicLibrarySP (*LoadPluginCallbackType) (const lldb::DebuggerSP &debugger_sp,
- const FileSpec& spec,
- Error& error);
+ typedef llvm::sys::DynamicLibrary (*LoadPluginCallbackType) (const lldb::DebuggerSP &debugger_sp,
+ const FileSpec& spec,
+ Error& error);
static lldb::DebuggerSP
CreateInstance (lldb::LogOutputCallback log_callback = NULL, void *baton = NULL);
@@ -352,6 +360,13 @@ public:
void
CancelForwardEvents (const lldb::ListenerSP &listener_sp);
+
+ bool
+ IsHandlingEvents () const
+ {
+ return IS_VALID_LLDB_HOST_THREAD(m_event_handler_thread);
+ }
+
protected:
friend class CommandInterpreter;
@@ -415,12 +430,11 @@ protected:
lldb::StreamSP m_log_callback_stream_sp;
ConstString m_instance_name;
static LoadPluginCallbackType g_load_plugin_callback;
- typedef std::vector<lldb::DynamicLibrarySP> LoadedPluginsList;
+ typedef std::vector<llvm::sys::DynamicLibrary> LoadedPluginsList;
LoadedPluginsList m_loaded_plugins;
lldb::thread_t m_event_handler_thread;
lldb::thread_t m_io_handler_thread;
lldb::ListenerSP m_forward_listener_sp;
- bool m_event_handler_thread_alive;
void
InstanceInitialize ();
diff --git a/include/lldb/Core/EmulateInstruction.h b/include/lldb/Core/EmulateInstruction.h
index 19a3269ae374..774d80968ff9 100644
--- a/include/lldb/Core/EmulateInstruction.h
+++ b/include/lldb/Core/EmulateInstruction.h
@@ -94,7 +94,7 @@ public:
enum ContextType
{
eContextInvalid = 0,
- // Read an instruciton opcode from memory
+ // Read an instruction opcode from memory
eContextReadOpcode,
// Usually used for writing a register value whose source value is an
@@ -223,13 +223,13 @@ public:
struct ISAAndImmediate
{
uint32_t isa;
- uint32_t unsigned_data32; // immdiate data
+ uint32_t unsigned_data32; // immediate data
} ISAAndImmediate;
struct ISAAndImmediateSigned
{
uint32_t isa;
- int32_t signed_data32; // signed immdiate data
+ int32_t signed_data32; // signed immediate data
} ISAAndImmediateSigned;
uint32_t isa;
@@ -409,7 +409,7 @@ public:
TestEmulation (Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data) = 0;
virtual bool
- GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo &reg_info) = 0;
+ GetRegisterInfo (lldb::RegisterKind reg_kind, uint32_t reg_num, RegisterInfo &reg_info) = 0;
//----------------------------------------------------------------------
// Optional overrides
@@ -421,7 +421,7 @@ public:
CreateFunctionEntryUnwind (UnwindPlan &unwind_plan);
static const char *
- TranslateRegister (uint32_t reg_kind, uint32_t reg_num, std::string &reg_name);
+ TranslateRegister (lldb::RegisterKind reg_kind, uint32_t reg_num, std::string &reg_name);
//----------------------------------------------------------------------
// RegisterInfo variants
@@ -449,25 +449,25 @@ public:
// Register kind and number variants
//----------------------------------------------------------------------
bool
- ReadRegister (uint32_t reg_kind,
+ ReadRegister (lldb::RegisterKind reg_kind,
uint32_t reg_num,
RegisterValue& reg_value);
bool
WriteRegister (const Context &context,
- uint32_t reg_kind,
+ lldb::RegisterKind reg_kind,
uint32_t reg_num,
const RegisterValue& reg_value);
uint64_t
- ReadRegisterUnsigned (uint32_t reg_kind,
+ ReadRegisterUnsigned (lldb::RegisterKind reg_kind,
uint32_t reg_num,
uint64_t fail_value,
bool *success_ptr);
bool
WriteRegisterUnsigned (const Context &context,
- uint32_t reg_kind,
+ lldb::RegisterKind reg_kind,
uint32_t reg_num,
uint64_t reg_value);
@@ -611,7 +611,7 @@ public:
static bool
GetBestRegisterKindAndNumber (const RegisterInfo *reg_info,
- uint32_t &reg_kind,
+ lldb::RegisterKind &reg_kind,
uint32_t &reg_num);
static uint32_t
diff --git a/include/lldb/Core/Error.h b/include/lldb/Core/Error.h
index 39c67f621c92..a1687689fc3f 100644
--- a/include/lldb/Core/Error.h
+++ b/include/lldb/Core/Error.h
@@ -209,6 +209,13 @@ public:
void
SetMachError (uint32_t err);
+
+ void
+ SetExpressionError (lldb::ExpressionResults, const char *mssg);
+
+ int
+ SetExpressionErrorWithFormat (lldb::ExpressionResults, const char *format, ...) __attribute__ ((format (printf, 3,4)));
+
//------------------------------------------------------------------
/// Set accesssor with an error value and type.
///
@@ -301,7 +308,7 @@ protected:
/// Member variables
//------------------------------------------------------------------
ValueType m_code; ///< Error code as an integer value.
- lldb::ErrorType m_type; ///< The type of the above error code.
+ lldb::ErrorType m_type; ///< The type of the above error code.
mutable std::string m_string; ///< A string representation of the error code.
};
diff --git a/include/lldb/Core/IOHandler.h b/include/lldb/Core/IOHandler.h
index 78d1e7447db4..f477ebd48007 100644
--- a/include/lldb/Core/IOHandler.h
+++ b/include/lldb/Core/IOHandler.h
@@ -73,7 +73,7 @@ namespace lldb_private {
// Called when CTRL+C is pressed which usually causes
// Debugger::DispatchInputInterrupt to be called.
- virtual void
+ virtual bool
Interrupt () = 0;
virtual void
@@ -191,7 +191,7 @@ namespace lldb_private {
///
/// This will return true if the input stream is a terminal (tty or
/// pty) and can cause IO handlers to do different things (like
- /// for a comfirmation when deleting all breakpoints).
+ /// for a confirmation when deleting all breakpoints).
//------------------------------------------------------------------
bool
GetIsInteractive ();
@@ -200,9 +200,9 @@ namespace lldb_private {
/// Check if the input is coming from a real terminal.
///
/// A real terminal has a valid size with a certain number of rows
- /// and colums. If this function returns true, then terminal escape
+ /// and columns. If this function returns true, then terminal escape
/// sequences are expected to work (cursor movement escape sequences,
- /// clearning lines, etc).
+ /// clearing lines, etc).
//------------------------------------------------------------------
bool
GetIsRealTerminal ();
@@ -267,7 +267,7 @@ namespace lldb_private {
//------------------------------------------------------------------
/// Called when a line or lines have been retrieved.
///
- /// This funtion can handle the current line and possibly call
+ /// This function can handle the current line and possibly call
/// IOHandler::SetIsDone(true) when the IO handler is done like when
/// "quit" is entered as a command, of when an empty line is
/// received. It is up to the delegate to determine when a line
@@ -304,11 +304,22 @@ namespace lldb_private {
virtual ConstString
- GetControlSequence (char ch)
+ IOHandlerGetControlSequence (char ch)
{
return ConstString();
}
+ //------------------------------------------------------------------
+ // Intercept the IOHandler::Interrupt() calls and do something.
+ //
+ // Return true if the interrupt was handled, false if the IOHandler
+ // should continue to try handle the interrupt itself.
+ //------------------------------------------------------------------
+ virtual bool
+ IOHandlerInterrupt (IOHandler &io_handler)
+ {
+ return false;
+ }
protected:
Completion m_completion; // Support for common builtin completions
bool m_io_handler_done;
@@ -338,7 +349,7 @@ namespace lldb_private {
}
virtual ConstString
- GetControlSequence (char ch)
+ IOHandlerGetControlSequence (char ch)
{
if (ch == 'd')
return ConstString (m_end_line + "\n");
@@ -364,7 +375,9 @@ namespace lldb_private {
// The last line was edited, if this line is empty, then we are done
// getting our multiple lines.
if (lines[line_idx] == m_end_line)
+ {
return LineStatus::Done;
+ }
}
return LineStatus::Success;
}
@@ -380,6 +393,7 @@ namespace lldb_private {
const char *editline_name, // Used for saving history files
const char *prompt,
bool multi_line,
+ uint32_t line_number_start, // If non-zero show line numbers starting at 'line_number_start'
IOHandlerDelegate &delegate);
IOHandlerEditline (Debugger &debugger,
@@ -390,6 +404,7 @@ namespace lldb_private {
const char *editline_name, // Used for saving history files
const char *prompt,
bool multi_line,
+ uint32_t line_number_start, // If non-zero show line numbers starting at 'line_number_start'
IOHandlerDelegate &delegate);
virtual
@@ -407,7 +422,7 @@ namespace lldb_private {
virtual void
Cancel ();
- virtual void
+ virtual bool
Interrupt ();
virtual void
@@ -423,7 +438,7 @@ namespace lldb_private {
virtual ConstString
GetControlSequence (char ch)
{
- return m_delegate.GetControlSequence (ch);
+ return m_delegate.IOHandlerGetControlSequence (ch);
}
virtual const char *
@@ -433,11 +448,14 @@ namespace lldb_private {
SetPrompt (const char *prompt);
bool
- GetLine (std::string &line);
+ GetLine (std::string &line, bool &interrupted);
bool
- GetLines (StringList &lines);
-
+ GetLines (StringList &lines, bool &interrupted);
+
+ void
+ SetBaseLineNumber (uint32_t line);
+
private:
static LineStatus
LineCompletedCallback (Editline *editline,
@@ -458,6 +476,7 @@ namespace lldb_private {
std::unique_ptr<Editline> m_editline_ap;
IOHandlerDelegate &m_delegate;
std::string m_prompt;
+ uint32_t m_base_line_number; // If non-zero, then show line numbers in prompt
bool m_multi_line;
};
@@ -517,7 +536,7 @@ namespace lldb_private {
virtual void
Cancel ();
- virtual void
+ virtual bool
Interrupt ();
virtual void
@@ -551,8 +570,8 @@ namespace lldb_private {
virtual void
Refresh ();
- virtual void
- Interrupt ();
+ virtual bool
+ HandleInterrupt ();
virtual void
GotEOF();
diff --git a/include/lldb/Core/Listener.h b/include/lldb/Core/Listener.h
index a12a65d705db..2dbd2eb436ce 100644
--- a/include/lldb/Core/Listener.h
+++ b/include/lldb/Core/Listener.h
@@ -76,7 +76,7 @@ public:
StopListeningForEvents (Broadcaster* broadcaster,
uint32_t event_mask);
- // Returns true if an event was recieved, false if we timed out.
+ // Returns true if an event was received, false if we timed out.
bool
WaitForEvent (const TimeValue *timeout,
lldb::EventSP &event_sp);
diff --git a/include/lldb/Core/Mangled.h b/include/lldb/Core/Mangled.h
index 8732dc00270c..7dc0eca3e8db 100644
--- a/include/lldb/Core/Mangled.h
+++ b/include/lldb/Core/Mangled.h
@@ -153,7 +153,7 @@ public:
/// demangled name to be computed currently (we don't use the accessor).
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
//----------------------------------------------------------------------
void
Dump (Stream *s) const;
@@ -162,7 +162,7 @@ public:
/// Dump a debug description of this object to a Stream \a s.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
//----------------------------------------------------------------------
void
DumpDebug (Stream *s) const;
@@ -219,7 +219,7 @@ public:
/// Which name would you prefer to get?
///
/// @return
- /// A const reference to the the preferred name string object if this
+ /// A const reference to the preferred name string object if this
/// object has a valid name of that kind, else a const reference to the
/// other name is returned.
//----------------------------------------------------------------------
diff --git a/include/lldb/Core/Module.h b/include/lldb/Core/Module.h
index 56650582791b..bfde7cbc5db9 100644
--- a/include/lldb/Core/Module.h
+++ b/include/lldb/Core/Module.h
@@ -68,7 +68,7 @@ public:
/// use ModuleList::GetSharedModule().
///
/// @param[in] file_spec
- /// The file specification for the on disk repesentation of
+ /// The file specification for the on disk representation of
/// this executable image.
///
/// @param[in] arch
@@ -88,10 +88,14 @@ public:
Module (const FileSpec& file_spec,
const ArchSpec& arch,
const ConstString *object_name = NULL,
- off_t object_offset = 0,
+ lldb::offset_t object_offset = 0,
const TimeValue *object_mod_time_ptr = NULL);
Module (const ModuleSpec &module_spec);
+
+ static lldb::ModuleSP
+ CreateJITModule (const lldb::ObjectFileJITDelegateSP &delegate_sp);
+
//------------------------------------------------------------------
/// Destructor.
//------------------------------------------------------------------
@@ -193,7 +197,7 @@ public:
/// in a module.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
//------------------------------------------------------------------
void
Dump (Stream *s);
@@ -415,7 +419,7 @@ public:
VariableList& variable_list);
//------------------------------------------------------------------
- /// Find global and static variables by regular exression.
+ /// Find global and static variables by regular expression.
///
/// @param[in] regex
/// A regular expression to use when matching the name.
@@ -468,11 +472,11 @@ public:
///
/// @param[in] type_name
/// The name of the type we are looking for that is a fully
- /// or partially qualfieid type name.
+ /// or partially qualified type name.
///
/// @param[in] exact_match
- /// If \b true, \a type_name is fully qualifed and must match
- /// exactly. If \b false, \a type_name is a partially qualfied
+ /// If \b true, \a type_name is fully qualified and must match
+ /// exactly. If \b false, \a type_name is a partially qualified
/// name where the leading namespaces or classes can be
/// omitted to make finding types that a user may type
/// easier.
@@ -700,14 +704,40 @@ public:
virtual SectionList *
GetSectionList ();
+ //------------------------------------------------------------------
+ /// Notify the module that the file addresses for the Sections have
+ /// been updated.
+ ///
+ /// If the Section file addresses for a module are updated, this
+ /// method should be called. Any parts of the module, object file,
+ /// or symbol file that has cached those file addresses must invalidate
+ /// or update its cache.
+ //------------------------------------------------------------------
+ virtual void
+ SectionFileAddressesChanged ();
+
uint32_t
GetVersion (uint32_t *versions, uint32_t num_versions);
- // Load an object file from memory.
+ //------------------------------------------------------------------
+ /// Load an object file from memory.
+ ///
+ /// If available, the size of the object file in memory may be
+ /// passed to avoid additional round trips to process memory.
+ /// If the size is not provided, a default value is used. This
+ /// value should be large enough to enable the ObjectFile plugins
+ /// to read the header of the object file without going back to the
+ /// process.
+ ///
+ /// @return
+ /// The object file loaded from memory or NULL, if the operation
+ /// failed (see the `error` for more information in that case).
+ //------------------------------------------------------------------
ObjectFile *
GetMemoryObjectFile (const lldb::ProcessSP &process_sp,
lldb::addr_t header_addr,
- Error &error);
+ Error &error,
+ size_t size_to_read = 512);
//------------------------------------------------------------------
/// Get the symbol vendor interface for the current architecture.
///
@@ -755,12 +785,12 @@ public:
/// A debugging function that will cause everything in a module to
/// be parsed.
///
- /// All compile units will be pasred, along with all globals and
+ /// All compile units will be parsed, along with all globals and
/// static variables and all functions for those compile units.
/// All types, scopes, local variables, static variables, global
/// variables, and line tables will be parsed. This can be used
/// prior to dumping a module to see a complete list of the
- /// resuling debug information that gets parsed, or as a debug
+ /// resulting debug information that gets parsed, or as a debug
/// function to ensure that the module can consume all of the
/// debug data the symbol vendor provides.
//------------------------------------------------------------------
@@ -948,7 +978,7 @@ public:
//------------------------------------------------------------------
// Return true if the file backing this module has changed since the
- // module was originally created since we saved the intial file
+ // module was originally created since we saved the initial file
// modification time when the module first gets created.
//------------------------------------------------------------------
bool
@@ -1156,7 +1186,9 @@ protected:
friend class SymbolFile;
private:
-
+
+ Module (); // Only used internally by CreateJITModule ()
+
size_t
FindTypes_Impl (const SymbolContext& sc,
const ConstString &name,
diff --git a/include/lldb/Core/ModuleList.h b/include/lldb/Core/ModuleList.h
index f03f79fb00ce..c3074d4d6510 100644
--- a/include/lldb/Core/ModuleList.h
+++ b/include/lldb/Core/ModuleList.h
@@ -15,6 +15,7 @@
#include "lldb/lldb-private.h"
#include "lldb/Host/Mutex.h"
+#include "lldb/Utility/Iterable.h"
namespace lldb_private {
@@ -137,7 +138,7 @@ public:
///
/// Clears the list of modules and releases a reference to each
/// module object and if the reference count goes to zero, the
- /// module will be deleted. Also relese all memory that might be
+ /// module will be deleted. Also release all memory that might be
/// held by any collection classes (like std::vector)
//------------------------------------------------------------------
void
@@ -149,7 +150,7 @@ public:
/// the supplied stream \a s.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
///
/// @see Module::Dump(Stream *) const
//------------------------------------------------------------------
@@ -307,7 +308,7 @@ public:
VariableList& variable_list) const;
//------------------------------------------------------------------
- /// Find global and static variables by regular exression.
+ /// Find global and static variables by regular expression.
///
/// @param[in] regex
/// A regular expression to use when matching the name.
@@ -577,6 +578,14 @@ protected:
Notifier* m_notifier;
+public:
+ typedef LockingAdaptedIterable<collection, lldb::ModuleSP, vector_adapter> ModuleIterable;
+ ModuleIterable
+ Modules()
+ {
+ return ModuleIterable(m_modules, GetMutex());
+ }
+
};
} // namespace lldb_private
diff --git a/include/lldb/Core/ModuleSpec.h b/include/lldb/Core/ModuleSpec.h
index dfeb7b73ca37..195fd991f8de 100644
--- a/include/lldb/Core/ModuleSpec.h
+++ b/include/lldb/Core/ModuleSpec.h
@@ -370,7 +370,6 @@ public:
if (dumped_something)
strm.PutCString(", ");
strm.Printf("object_mod_time = 0x%" PRIx64, m_object_mod_time.GetAsSecondsSinceJan1_1970());
- dumped_something = true;
}
}
@@ -387,14 +386,15 @@ public:
if (!FileSpec::Equal(fspec, GetFileSpec(), fspec.GetDirectory().IsEmpty() == false))
return false;
}
- if (match_module_spec.GetPlatformFileSpecPtr())
+ if (GetPlatformFileSpec() && match_module_spec.GetPlatformFileSpecPtr())
{
const FileSpec &fspec = match_module_spec.GetPlatformFileSpec();
if (!FileSpec::Equal(fspec, GetPlatformFileSpec(), fspec.GetDirectory().IsEmpty() == false))
return false;
}
- if (match_module_spec.GetSymbolFileSpecPtr())
+ // Only match the symbol file spec if there is one in this ModuleSpec
+ if (GetSymbolFileSpec() && match_module_spec.GetSymbolFileSpecPtr())
{
const FileSpec &fspec = match_module_spec.GetSymbolFileSpec();
if (!FileSpec::Equal(fspec, GetSymbolFileSpec(), fspec.GetDirectory().IsEmpty() == false))
diff --git a/include/lldb/Core/PluginManager.h b/include/lldb/Core/PluginManager.h
index e02f43f4fa8b..a2ac67bf9f25 100644
--- a/include/lldb/Core/PluginManager.h
+++ b/include/lldb/Core/PluginManager.h
@@ -80,6 +80,24 @@ public:
GetDynamicLoaderCreateCallbackForPluginName (const ConstString &name);
//------------------------------------------------------------------
+ // JITLoader
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ JITLoaderCreateInstance create_callback,
+ DebuggerInitializeCallback debugger_init_callback = NULL);
+
+ static bool
+ UnregisterPlugin (JITLoaderCreateInstance create_callback);
+
+ static JITLoaderCreateInstance
+ GetJITLoaderCreateCallbackAtIndex (uint32_t idx);
+
+ static JITLoaderCreateInstance
+ GetJITLoaderCreateCallbackForPluginName (const ConstString &name);
+
+ //------------------------------------------------------------------
// EmulateInstruction
//------------------------------------------------------------------
static bool
@@ -157,7 +175,8 @@ public:
const char *description,
ObjectFileCreateInstance create_callback,
ObjectFileCreateMemoryInstance create_memory_callback,
- ObjectFileGetModuleSpecifications get_module_specifications);
+ ObjectFileGetModuleSpecifications get_module_specifications,
+ ObjectFileSaveCore save_core = NULL);
static bool
UnregisterPlugin (ObjectFileCreateInstance create_callback);
@@ -177,6 +196,8 @@ public:
static ObjectFileCreateMemoryInstance
GetObjectFileCreateMemoryCallbackForPluginName (const ConstString &name);
+ static Error
+ SaveCore (const lldb::ProcessSP &process_sp, const FileSpec &outfile);
//------------------------------------------------------------------
// ObjectContainer
diff --git a/include/lldb/Core/RegisterValue.h b/include/lldb/Core/RegisterValue.h
index cf29cea46d36..1b1a71a11c5a 100644
--- a/include/lldb/Core/RegisterValue.h
+++ b/include/lldb/Core/RegisterValue.h
@@ -374,6 +374,12 @@ namespace lldb_private {
uint32_t
GetByteSize () const;
+ static uint32_t
+ GetMaxByteSize ()
+ {
+ return kMaxRegisterByteSize;
+ }
+
void
Clear();
diff --git a/include/lldb/Core/RegularExpression.h b/include/lldb/Core/RegularExpression.h
index c116d439b94a..8e36811fa750 100644
--- a/include/lldb/Core/RegularExpression.h
+++ b/include/lldb/Core/RegularExpression.h
@@ -119,7 +119,7 @@ public:
RegularExpression ();
//------------------------------------------------------------------
- /// Constructor that takes a regulare expression with flags.
+ /// Constructor that takes a regular expression with flags.
///
/// Constructor that compiles \a re using \a flags and stores the
/// resulting compiled regular expression into this object.
@@ -129,7 +129,7 @@ public:
/// compile.
///
/// @param[in] flags
- /// Flags that are passed the the \c regcomp() function.
+ /// Flags that are passed to the \c regcomp() function.
//------------------------------------------------------------------
explicit
RegularExpression (const char* re, int flags);
@@ -141,7 +141,7 @@ public:
//------------------------------------------------------------------
/// Destructor.
///
- /// Any previosuly compiled regular expression contained in this
+ /// Any previously compiled regular expression contained in this
/// object will be freed.
//------------------------------------------------------------------
~RegularExpression ();
@@ -154,10 +154,10 @@ public:
/// Compile a regular expression.
///
/// Compile a regular expression using the supplied regular
- /// expression text and flags. The compied regular expression lives
+ /// expression text and flags. The compiled regular expression lives
/// in this object so that it can be readily used for regular
/// expression matches. Execute() can be called after the regular
- /// expression is compiled. Any previosuly compiled regular
+ /// expression is compiled. Any previously compiled regular
/// expression contained in this object will be freed.
///
/// @param[in] re
@@ -165,7 +165,7 @@ public:
/// expression to compile.
///
/// @param[in] flags
- /// Flags that are passed the the \c regcomp() function.
+ /// Flags that are passed to the \c regcomp() function.
///
/// @return
/// \b true if the regular expression compiles successfully,
diff --git a/include/lldb/Core/Section.h b/include/lldb/Core/Section.h
index 437eaf59b9c4..32dac5f35b84 100644
--- a/include/lldb/Core/Section.h
+++ b/include/lldb/Core/Section.h
@@ -119,6 +119,7 @@ public:
lldb::addr_t vm_size,
lldb::offset_t file_offset,
lldb::offset_t file_size,
+ uint32_t log2align,
uint32_t flags);
// Create a section that is a child of parent_section_sp
@@ -132,6 +133,7 @@ public:
lldb::addr_t vm_size,
lldb::offset_t file_offset,
lldb::offset_t file_size,
+ uint32_t log2align,
uint32_t flags);
~Section ();
@@ -284,6 +286,17 @@ public:
return m_obj_file;
}
+ uint32_t GetLog2Align()
+ {
+ return m_log2align;
+ }
+
+ void
+ SetLog2Align(uint32_t align)
+ {
+ m_log2align = align;
+ }
+
protected:
@@ -296,6 +309,7 @@ protected:
lldb::addr_t m_byte_size; // Size in bytes that this section will occupy in memory at runtime
lldb::offset_t m_file_offset; // Object file offset (if any)
lldb::offset_t m_file_size; // Object file size (can be smaller than m_byte_size for zero filled sections...)
+ uint32_t m_log2align; // log_2(align) of the section (i.e. section has to be aligned to 2^m_log2align)
SectionList m_children; // Child sections
bool m_fake:1, // If true, then this section only can contain the address if one of its
// children contains an address. This allows for gaps between the children
diff --git a/include/lldb/Core/SourceManager.h b/include/lldb/Core/SourceManager.h
index d8c9eccd3477..0f65be1bee4b 100644
--- a/include/lldb/Core/SourceManager.h
+++ b/include/lldb/Core/SourceManager.h
@@ -85,7 +85,7 @@ public:
CalculateLineOffsets (uint32_t line = UINT32_MAX);
FileSpec m_file_spec_orig; // The original file spec that was used (can be different from m_file_spec)
- FileSpec m_file_spec; // The actualy file spec being used (if the target has source mappings, this might be different from m_file_spec_orig)
+ FileSpec m_file_spec; // The actually file spec being used (if the target has source mappings, this might be different from m_file_spec_orig)
TimeValue m_mod_time; // Keep the modification time that this file data is valid for
uint32_t m_source_map_mod_id; // If the target uses path remappings, be sure to clear our notion of a source file if the path modification ID changes
lldb::DataBufferSP m_data_sp;
diff --git a/include/lldb/Core/Stream.h b/include/lldb/Core/Stream.h
index 0fd4aac041a9..11780aa6ff0f 100644
--- a/include/lldb/Core/Stream.h
+++ b/include/lldb/Core/Stream.h
@@ -472,7 +472,7 @@ public:
/// Indent the current line in the stream.
///
/// Indent the current line using the current indentation level and
- /// print an optional string following the idenatation spaces.
+ /// print an optional string following the indentation spaces.
///
/// @param[in] s
/// A C string to print following the indentation. If NULL, just
diff --git a/include/lldb/Core/StructuredData.h b/include/lldb/Core/StructuredData.h
new file mode 100644
index 000000000000..a4cabf4fe352
--- /dev/null
+++ b/include/lldb/Core/StructuredData.h
@@ -0,0 +1,486 @@
+//===-- StructuredData.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_StructuredData_h_
+#define liblldb_StructuredData_h_
+
+// C Includes
+// C++ Includes
+
+#include <map>
+#include <utility>
+#include <vector>
+#include <string>
+
+#include "llvm/ADT/StringRef.h"
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-defines.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Stream.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class StructuredData StructuredData.h "lldb/Core/StructuredData.h"
+/// @brief A class which can hold structured data
+///
+/// The StructuredData class is designed to hold the data from a JSON
+/// or plist style file -- a serialized data structure with dictionaries
+/// (maps, hashes), arrays, and concrete values like integers, floating
+/// point numbers, strings, booleans.
+///
+/// StructuredData does not presuppose any knowledge of the schema for
+/// the data it is holding; it can parse JSON data, for instance, and
+/// other parts of lldb can iterate through the parsed data set to find
+/// keys and values that may be present.
+//----------------------------------------------------------------------
+
+class StructuredData
+{
+public:
+
+ class Object;
+ class Array;
+ class Integer;
+ class Float;
+ class Boolean;
+ class String;
+ class Dictionary;
+
+ typedef std::shared_ptr<Object> ObjectSP;
+ typedef std::shared_ptr<Array> ArraySP;
+ typedef std::shared_ptr<Dictionary> DictionarySP;
+
+ enum class Type {
+ eTypeInvalid = -1,
+ eTypeNull = 0,
+ eTypeArray,
+ eTypeInteger,
+ eTypeFloat,
+ eTypeBoolean,
+ eTypeString,
+ eTypeDictionary
+ };
+
+ class Object :
+ public std::enable_shared_from_this<Object>
+ {
+ public:
+
+ Object (Type t = Type::eTypeInvalid) :
+ m_type (t)
+ {
+ }
+
+ virtual ~Object ()
+ {
+ }
+
+ virtual void
+ Clear ()
+ {
+ m_type = Type::eTypeInvalid;
+ }
+
+ Type
+ GetType () const
+ {
+ return m_type;
+ }
+
+ void
+ SetType (Type t)
+ {
+ m_type = t;
+ }
+
+ Array *
+ GetAsArray ()
+ {
+ if (m_type == Type::eTypeArray)
+ return (Array *)this;
+ return NULL;
+ }
+
+ Dictionary *
+ GetAsDictionary ()
+ {
+ if (m_type == Type::eTypeDictionary)
+ return (Dictionary *)this;
+ return NULL;
+ }
+
+ Integer *
+ GetAsInteger ()
+ {
+ if (m_type == Type::eTypeInteger)
+ return (Integer *)this;
+ return NULL;
+ }
+
+ Float *
+ GetAsFloat ()
+ {
+ if (m_type == Type::eTypeFloat)
+ return (Float *)this;
+ return NULL;
+ }
+
+ Boolean *
+ GetAsBoolean ()
+ {
+ if (m_type == Type::eTypeBoolean)
+ return (Boolean *)this;
+ return NULL;
+ }
+
+ String *
+ GetAsString ()
+ {
+ if (m_type == Type::eTypeString)
+ return (String *)this;
+ return NULL;
+ }
+
+ ObjectSP
+ GetObjectForDotSeparatedPath (llvm::StringRef path);
+
+ virtual void
+ Dump (Stream &s) const = 0;
+
+ private:
+ Type m_type;
+ };
+
+ class Array : public Object
+ {
+ public:
+ Array () :
+ Object (Type::eTypeArray)
+ {
+ }
+
+ virtual
+ ~Array()
+ {
+ }
+
+ size_t
+ GetSize()
+ {
+ return m_items.size();
+ }
+
+ ObjectSP
+ operator[](size_t idx)
+ {
+ if (idx < m_items.size())
+ return m_items[idx];
+ return ObjectSP();
+ }
+
+ ObjectSP
+ GetItemAtIndex (size_t idx)
+ {
+ if (idx < m_items.size())
+ return m_items[idx];
+ return ObjectSP();
+ }
+
+ void
+ Push(ObjectSP item)
+ {
+ m_items.push_back(item);
+ }
+
+ void
+ AddItem(ObjectSP item)
+ {
+ m_items.push_back(item);
+ }
+
+ virtual void
+ Dump (Stream &s) const;
+
+ protected:
+ typedef std::vector<ObjectSP> collection;
+ collection m_items;
+ };
+
+
+ class Integer : public Object
+ {
+ public:
+ Integer () :
+ Object (Type::eTypeInteger),
+ m_value ()
+ {
+ }
+
+ virtual ~Integer()
+ {
+ }
+
+ void
+ SetValue (uint64_t value)
+ {
+ m_value = value;
+ }
+
+ uint64_t
+ GetValue ()
+ {
+ return m_value;
+ }
+
+ virtual void
+ Dump (Stream &s) const;
+
+ protected:
+ uint64_t m_value;
+ };
+
+ class Float : public Object
+ {
+ public:
+ Float () :
+ Object (Type::eTypeFloat),
+ m_value ()
+ {
+ }
+
+ virtual ~Float()
+ {
+ }
+
+ void
+ SetValue (double value)
+ {
+ m_value = value;
+ }
+
+ double
+ GetValue ()
+ {
+ return m_value;
+ }
+
+ virtual void
+ Dump (Stream &s) const;
+
+ protected:
+ double m_value;
+ };
+
+ class Boolean : public Object
+ {
+ public:
+ Boolean () :
+ Object (Type::eTypeBoolean),
+ m_value ()
+ {
+ }
+
+ virtual ~Boolean()
+ {
+ }
+
+ void
+ SetValue (bool value)
+ {
+ m_value = value;
+ }
+
+ bool
+ GetValue ()
+ {
+ return m_value;
+ }
+
+ virtual void
+ Dump (Stream &s) const;
+
+ protected:
+ bool m_value;
+ };
+
+
+
+ class String : public Object
+ {
+ public:
+ String () :
+ Object (Type::eTypeString),
+ m_value ()
+ {
+ }
+
+ void
+ SetValue (std::string string)
+ {
+ m_value = string;
+ }
+
+ std::string
+ GetValue ()
+ {
+ return m_value;
+ }
+
+ virtual void
+ Dump (Stream &s) const;
+
+ protected:
+ std::string m_value;
+ };
+
+ class Dictionary : public Object
+ {
+ public:
+ Dictionary () :
+ Object (Type::eTypeDictionary),
+ m_dict ()
+ {
+ }
+
+ virtual ~Dictionary()
+ {
+ }
+ size_t
+ GetSize()
+ {
+ return m_dict.size();
+ }
+
+ ObjectSP
+ GetKeys()
+ {
+ ObjectSP object_sp(new Array ());
+ Array *array = object_sp->GetAsArray();
+ collection::const_iterator iter;
+ for (iter = m_dict.begin(); iter != m_dict.end(); ++iter)
+ {
+ ObjectSP key_object_sp(new String());
+ key_object_sp->GetAsString()->SetValue(iter->first.AsCString());
+ array->Push(key_object_sp);
+ }
+ return object_sp;
+ }
+
+ ObjectSP
+ GetValueForKey (const char *key)
+ {
+ ObjectSP value_sp;
+ if (key)
+ {
+ ConstString key_cs(key);
+ for (collection::const_iterator iter = m_dict.begin(); iter != m_dict.end(); ++iter)
+ {
+ if (key_cs == iter->first)
+ {
+ value_sp = iter->second;
+ break;
+ }
+ }
+ }
+ return value_sp;
+ }
+
+ bool
+ HasKey (const char *key)
+ {
+ ConstString key_cs (key);
+ collection::const_iterator search = m_dict.find(key_cs);
+ if (search != m_dict.end())
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ void
+ AddItem (const char *key, ObjectSP value)
+ {
+ ConstString key_cs(key);
+ m_dict[key_cs] = value;
+ }
+
+ void
+ AddIntegerItem (const char *key, uint64_t value)
+ {
+ ObjectSP val_obj (new Integer());
+ val_obj->GetAsInteger()->SetValue (value);
+ AddItem (key, val_obj);
+ }
+
+ void
+ AddFloatItem (const char *key, double value)
+ {
+ ObjectSP val_obj (new Float());
+ val_obj->GetAsFloat()->SetValue (value);
+ AddItem (key, val_obj);
+ }
+
+ void
+ AddStringItem (const char *key, std::string value)
+ {
+ ObjectSP val_obj (new String());
+ val_obj->GetAsString()->SetValue (value);
+ AddItem (key, val_obj);
+ }
+
+ void
+ AddBooleanItem (const char *key, bool value)
+ {
+ ObjectSP val_obj (new Boolean());
+ val_obj->GetAsBoolean()->SetValue (value);
+ AddItem (key, val_obj);
+ }
+
+ virtual void
+ Dump (Stream &s) const;
+
+ protected:
+ typedef std::map<ConstString, ObjectSP> collection;
+ collection m_dict;
+ };
+
+ class Null : public Object
+ {
+ public:
+ Null () :
+ Object (Type::eTypeNull)
+ {
+ }
+
+ virtual ~Null()
+ {
+ }
+
+ virtual void
+ Dump (Stream &s) const;
+
+ protected:
+ };
+
+
+ static ObjectSP
+ ParseJSON (std::string json_text);
+
+}; // class StructuredData
+
+
+} // namespace lldb_private
+
+#endif // liblldb_StructuredData_h_
diff --git a/include/lldb/Core/UserID.h b/include/lldb/Core/UserID.h
index ea6af74759bf..230e43fa551f 100644
--- a/include/lldb/Core/UserID.h
+++ b/include/lldb/Core/UserID.h
@@ -19,12 +19,12 @@ namespace lldb_private {
/// @class UserID UserID.h "lldb/Core/UserID.h"
/// @brief A mix in class that contains a generic user ID.
///
-/// UserID is desinged as a mix in class that can contain an integer
-/// based unique identifier for a varietly of objects in lldb.
+/// UserID is designed as a mix in class that can contain an integer
+/// based unique identifier for a variety of objects in lldb.
///
/// The value for this identifier is chosen by each parser plug-in. A
/// value should be chosen that makes sense for each kind of object
-/// should and allows quick access to further and more in depth parsing.
+/// and should allow quick access to further and more in depth parsing.
///
/// Symbol table entries can use this to store the original symbol table
/// index, functions can use it to store the symbol table index or the
diff --git a/include/lldb/Core/Value.h b/include/lldb/Core/Value.h
index c7d44322333c..957cedeb0dcc 100644
--- a/include/lldb/Core/Value.h
+++ b/include/lldb/Core/Value.h
@@ -124,9 +124,15 @@ public:
Value();
Value(const Scalar& scalar);
Value(const Vector& vector);
- Value(const uint8_t *bytes, int len);
+ Value(const void *bytes, int len);
Value(const Value &rhs);
+ void
+ SetBytes (const void *bytes, int len);
+
+ void
+ AppendBytes (const void *bytes, int len);
+
Value &
operator=(const Value &rhs);
@@ -232,8 +238,23 @@ public:
return false;
}
- void
+ size_t
ResizeData(size_t len);
+
+ size_t
+ AppendDataToHostBuffer (const Value &rhs);
+
+ DataBufferHeap &
+ GetBuffer ()
+ {
+ return m_data_buffer;
+ }
+
+ const DataBufferHeap &
+ GetBuffer () const
+ {
+ return m_data_buffer;
+ }
bool
ValueOf(ExecutionContext *exe_ctx);
diff --git a/include/lldb/Core/ValueObject.h b/include/lldb/Core/ValueObject.h
index e2847c778484..6a08ec6507f9 100644
--- a/include/lldb/Core/ValueObject.h
+++ b/include/lldb/Core/ValueObject.h
@@ -35,7 +35,7 @@ namespace lldb_private {
/// ValueObject:
///
/// This abstract class provides an interface to a particular value, be it a register, a local or global variable,
-/// that is evaluated in some particular scope. The ValueObject also has the capibility of being the "child" of
+/// that is evaluated in some particular scope. The ValueObject also has the capability of being the "child" of
/// some other variable object, and in turn of having children.
/// If a ValueObject is a root variable object - having no parent - then it must be constructed with respect to some
/// particular ExecutionContextScope. If it is a child, it inherits the ExecutionContextScope from its parent.
@@ -380,7 +380,7 @@ public:
GetTypeImpl ();
//------------------------------------------------------------------
- // Sublasses must implement the functions below.
+ // Subclasses must implement the functions below.
//------------------------------------------------------------------
virtual uint64_t
GetByteSize() = 0;
@@ -389,12 +389,15 @@ public:
GetValueType() const = 0;
//------------------------------------------------------------------
- // Sublasses can implement the functions below.
+ // Subclasses can implement the functions below.
//------------------------------------------------------------------
virtual ConstString
GetTypeName();
virtual ConstString
+ GetDisplayTypeName();
+
+ virtual ConstString
GetQualifiedTypeName();
virtual lldb::LanguageType
@@ -427,6 +430,9 @@ public:
return false;
}
+ bool
+ IsBaseClass (uint32_t& depth);
+
virtual bool
IsDereferenceOfParent ()
{
@@ -465,7 +471,7 @@ public:
return true;
}
- virtual off_t
+ virtual lldb::offset_t
GetByteOffset()
{
return 0;
@@ -528,7 +534,7 @@ public:
GetDeclaration (Declaration &decl);
//------------------------------------------------------------------
- // The functions below should NOT be modified by sublasses
+ // The functions below should NOT be modified by subclasses
//------------------------------------------------------------------
const Error &
GetError();
@@ -671,6 +677,9 @@ public:
GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type, bool can_create);
virtual lldb::ValueObjectSP
+ GetSyntheticBase (uint32_t offset, const ClangASTType& type, bool can_create);
+
+ virtual lldb::ValueObjectSP
GetDynamicValue (lldb::DynamicValueType valueType);
lldb::DynamicValueType
@@ -712,6 +721,10 @@ public:
{
}
+ // Find the address of the C++ vtable pointer
+ virtual lldb::addr_t
+ GetCPPVTableAddress(AddressType &address_type);
+
virtual lldb::ValueObjectSP
Cast (const ClangASTType &clang_ast_type);
@@ -762,7 +775,7 @@ public:
static lldb::ValueObjectSP
CreateValueObjectFromData (const char* name,
- DataExtractor& data,
+ const DataExtractor& data,
const ExecutionContext& exe_ctx,
ClangASTType type);
@@ -793,7 +806,7 @@ public:
uint32_t item_count = 1);
virtual uint64_t
- GetData (DataExtractor& data);
+ GetData (DataExtractor& data, Error &error);
virtual bool
SetData (DataExtractor &data, Error &error);
@@ -961,7 +974,7 @@ protected:
void
SetChildrenCount (size_t count)
{
- m_children_count = count;
+ Clear(count);
}
size_t
@@ -971,10 +984,10 @@ protected:
}
void
- Clear()
+ Clear(size_t new_count = 0)
{
- m_children_count = 0;
Mutex::Locker locker(m_mutex);
+ m_children_count = new_count;
m_children.clear();
}
@@ -1127,7 +1140,7 @@ protected:
ClearDynamicTypeInformation ();
//------------------------------------------------------------------
- // Sublasses must implement the functions below.
+ // Subclasses must implement the functions below.
//------------------------------------------------------------------
virtual ClangASTType
diff --git a/include/lldb/Core/ValueObjectChild.h b/include/lldb/Core/ValueObjectChild.h
index 780529a4af11..07d1f294bd80 100644
--- a/include/lldb/Core/ValueObjectChild.h
+++ b/include/lldb/Core/ValueObjectChild.h
@@ -32,7 +32,7 @@ public:
return m_byte_size;
}
- virtual off_t
+ virtual lldb::offset_t
GetByteOffset()
{
return m_byte_offset;
@@ -62,6 +62,9 @@ public:
virtual ConstString
GetQualifiedTypeName();
+ virtual ConstString
+ GetDisplayTypeName();
+
virtual bool
IsInScope ();
diff --git a/include/lldb/Core/ValueObjectConstResult.h b/include/lldb/Core/ValueObjectConstResult.h
index 4964d0589a09..dd87fc848ae8 100644
--- a/include/lldb/Core/ValueObjectConstResult.h
+++ b/include/lldb/Core/ValueObjectConstResult.h
@@ -80,6 +80,9 @@ public:
virtual ConstString
GetTypeName();
+ virtual ConstString
+ GetDisplayTypeName();
+
virtual bool
IsInScope ();
diff --git a/include/lldb/Core/ValueObjectDynamicValue.h b/include/lldb/Core/ValueObjectDynamicValue.h
index 68f88c96e545..7607bd38137d 100644
--- a/include/lldb/Core/ValueObjectDynamicValue.h
+++ b/include/lldb/Core/ValueObjectDynamicValue.h
@@ -37,6 +37,9 @@ public:
virtual ConstString
GetQualifiedTypeName();
+
+ virtual ConstString
+ GetDisplayTypeName();
virtual size_t
CalculateNumChildren();
diff --git a/include/lldb/Core/ValueObjectMemory.h b/include/lldb/Core/ValueObjectMemory.h
index 627d73eb4b27..41b43188a46a 100644
--- a/include/lldb/Core/ValueObjectMemory.h
+++ b/include/lldb/Core/ValueObjectMemory.h
@@ -47,6 +47,9 @@ public:
virtual ConstString
GetTypeName();
+ virtual ConstString
+ GetDisplayTypeName();
+
virtual size_t
CalculateNumChildren();
diff --git a/include/lldb/Core/ValueObjectRegister.h b/include/lldb/Core/ValueObjectRegister.h
index 6820629f08e1..f7c7683d60bc 100644
--- a/include/lldb/Core/ValueObjectRegister.h
+++ b/include/lldb/Core/ValueObjectRegister.h
@@ -45,6 +45,9 @@ public:
virtual ConstString
GetQualifiedTypeName();
+
+ virtual ConstString
+ GetDisplayTypeName();
virtual size_t
CalculateNumChildren();
diff --git a/include/lldb/Core/ValueObjectSyntheticFilter.h b/include/lldb/Core/ValueObjectSyntheticFilter.h
index f1d8c885c255..e12698f49bb1 100644
--- a/include/lldb/Core/ValueObjectSyntheticFilter.h
+++ b/include/lldb/Core/ValueObjectSyntheticFilter.h
@@ -41,6 +41,9 @@ public:
virtual ConstString
GetQualifiedTypeName();
+
+ virtual ConstString
+ GetDisplayTypeName();
virtual bool
MightHaveChildren();
diff --git a/include/lldb/Core/ValueObjectVariable.h b/include/lldb/Core/ValueObjectVariable.h
index 8a30b00f6bbd..0e32d09057dc 100644
--- a/include/lldb/Core/ValueObjectVariable.h
+++ b/include/lldb/Core/ValueObjectVariable.h
@@ -39,6 +39,9 @@ public:
virtual ConstString
GetQualifiedTypeName();
+
+ virtual ConstString
+ GetDisplayTypeName();
virtual size_t
CalculateNumChildren();
diff --git a/include/lldb/Core/dwarf.h b/include/lldb/Core/dwarf.h
index 91c8dfb9d0da..9fa8816229a9 100644
--- a/include/lldb/Core/dwarf.h
+++ b/include/lldb/Core/dwarf.h
@@ -12,7 +12,7 @@
#include <stdint.h>
-// Get the DWARF constant defintions from llvm
+// Get the DWARF constant definitions from llvm
#include "llvm/Support/Dwarf.h"
// and stuff them in our default namespace
using namespace llvm::dwarf;
diff --git a/include/lldb/DataFormatters/CXXFormatterFunctions.h b/include/lldb/DataFormatters/CXXFormatterFunctions.h
index c53ef9589eea..753ffa1bae1b 100644
--- a/include/lldb/DataFormatters/CXXFormatterFunctions.h
+++ b/include/lldb/DataFormatters/CXXFormatterFunctions.h
@@ -19,6 +19,7 @@
#include "lldb/DataFormatters/FormatClasses.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
#include "clang/AST/ASTContext.h"
@@ -26,6 +27,9 @@
namespace lldb_private {
namespace formatters
{
+ StackFrame*
+ GetViableFrame (ExecutionContext exe_ctx);
+
bool
ExtractValueFromObjCExpression (ValueObject &valobj,
const char* target_type,
@@ -140,6 +144,9 @@ namespace lldb_private {
NSStringSummaryProvider (ValueObject& valobj, Stream& stream);
bool
+ NSTaggedString_SummaryProvider (ObjCLanguageRuntime::ClassDescriptorSP descriptor, Stream& stream);
+
+ bool
NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream);
bool
@@ -176,113 +183,6 @@ namespace lldb_private {
extern template bool
ObjCSELSummaryProvider<false> (ValueObject&, Stream&);
- class NSArrayMSyntheticFrontEnd : public SyntheticChildrenFrontEnd
- {
- private:
- struct DataDescriptor_32
- {
- uint32_t _used;
- uint32_t _priv1 : 2 ;
- uint32_t _size : 30;
- uint32_t _priv2 : 2;
- uint32_t offset : 30;
- uint32_t _priv3;
- uint32_t _data;
- };
- struct DataDescriptor_64
- {
- uint64_t _used;
- uint64_t _priv1 : 2 ;
- uint64_t _size : 62;
- uint64_t _priv2 : 2;
- uint64_t offset : 62;
- uint32_t _priv3;
- uint64_t _data;
- };
- public:
- NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
-
- virtual size_t
- CalculateNumChildren ();
-
- virtual lldb::ValueObjectSP
- GetChildAtIndex (size_t idx);
-
- virtual bool
- Update();
-
- virtual bool
- MightHaveChildren ();
-
- virtual size_t
- GetIndexOfChildWithName (const ConstString &name);
-
- virtual
- ~NSArrayMSyntheticFrontEnd ();
- private:
- ExecutionContextRef m_exe_ctx_ref;
- uint8_t m_ptr_size;
- DataDescriptor_32 *m_data_32;
- DataDescriptor_64 *m_data_64;
- ClangASTType m_id_type;
- std::vector<lldb::ValueObjectSP> m_children;
- };
-
- class NSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd
- {
- public:
- NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
-
- virtual size_t
- CalculateNumChildren ();
-
- virtual lldb::ValueObjectSP
- GetChildAtIndex (size_t idx);
-
- virtual bool
- Update();
-
- virtual bool
- MightHaveChildren ();
-
- virtual size_t
- GetIndexOfChildWithName (const ConstString &name);
-
- virtual
- ~NSArrayISyntheticFrontEnd ();
- private:
- ExecutionContextRef m_exe_ctx_ref;
- uint8_t m_ptr_size;
- uint64_t m_items;
- lldb::addr_t m_data_ptr;
- ClangASTType m_id_type;
- std::vector<lldb::ValueObjectSP> m_children;
- };
-
- class NSArrayCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd
- {
- public:
- NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
-
- virtual size_t
- CalculateNumChildren ();
-
- virtual lldb::ValueObjectSP
- GetChildAtIndex (size_t idx);
-
- virtual bool
- Update();
-
- virtual bool
- MightHaveChildren ();
-
- virtual size_t
- GetIndexOfChildWithName (const ConstString &name);
-
- virtual
- ~NSArrayCodeRunningSyntheticFrontEnd ();
- };
-
SyntheticChildrenFrontEnd* NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd
diff --git a/include/lldb/DataFormatters/FormatManager.h b/include/lldb/DataFormatters/FormatManager.h
index 24ec877ee515..0b9144dffa17 100644
--- a/include/lldb/DataFormatters/FormatManager.h
+++ b/include/lldb/DataFormatters/FormatManager.h
@@ -25,6 +25,7 @@
#include "lldb/DataFormatters/TypeCategoryMap.h"
#include <atomic>
+#include <functional>
namespace lldb_private {
@@ -39,6 +40,14 @@ class FormatManager : public IFormatChangeListener
typedef TypeCategoryMap::MapType::iterator CategoryMapIterator;
public:
+ template <typename FormatterType>
+ using HardcodedFormatterFinder = std::function<typename FormatterType::SharedPointer (lldb_private::ValueObject&,
+ lldb::DynamicValueType,
+ FormatManager&)>;
+
+ template <typename FormatterType>
+ using HardcodedFormatterFinders = std::vector<HardcodedFormatterFinder<FormatterType>>;
+
typedef TypeCategoryMap::CallbackType CategoryCallback;
FormatManager ();
@@ -260,6 +269,19 @@ private:
ConstString m_vectortypes_category_name;
ConstString m_appkit_category_name;
+ HardcodedFormatterFinders<TypeFormatImpl> m_hardcoded_formats;
+ HardcodedFormatterFinders<TypeSummaryImpl> m_hardcoded_summaries;
+ HardcodedFormatterFinders<SyntheticChildren> m_hardcoded_synthetics;
+
+ lldb::TypeFormatImplSP
+ GetHardcodedFormat (ValueObject&,lldb::DynamicValueType);
+
+ lldb::TypeSummaryImplSP
+ GetHardcodedSummaryFormat (ValueObject&,lldb::DynamicValueType);
+
+ lldb::SyntheticChildrenSP
+ GetHardcodedSyntheticChildren (ValueObject&,lldb::DynamicValueType);
+
TypeCategoryMap&
GetCategories ()
{
@@ -281,8 +303,11 @@ private:
void
LoadObjCFormatters ();
+
+ void
+ LoadHardcodedFormatters ();
};
} // namespace lldb_private
-
+
#endif // lldb_FormatManager_h_
diff --git a/include/lldb/DataFormatters/TypeFormat.h b/include/lldb/DataFormatters/TypeFormat.h
index 20fa8f2d4e7f..1090d7843e53 100644
--- a/include/lldb/DataFormatters/TypeFormat.h
+++ b/include/lldb/DataFormatters/TypeFormat.h
@@ -14,6 +14,7 @@
// C++ Includes
#include <string>
+#include <unordered_map>
// Other libraries and framework includes
@@ -135,7 +136,7 @@ namespace lldb_private {
typedef std::shared_ptr<TypeFormatImpl> SharedPointer;
typedef bool(*ValueCallback)(void*, ConstString, const lldb::TypeFormatImplSP&);
- virtual ~TypeFormatImpl () = default;
+ virtual ~TypeFormatImpl ();
bool
Cascades () const
@@ -229,7 +230,7 @@ namespace lldb_private {
typedef std::shared_ptr<TypeFormatImpl_Format> SharedPointer;
typedef bool(*ValueCallback)(void*, ConstString, const TypeFormatImpl_Format::SharedPointer&);
- virtual ~TypeFormatImpl_Format () = default;
+ virtual ~TypeFormatImpl_Format ();
lldb::Format
GetFormat () const
@@ -272,7 +273,7 @@ namespace lldb_private {
typedef std::shared_ptr<TypeFormatImpl_EnumType> SharedPointer;
typedef bool(*ValueCallback)(void*, ConstString, const TypeFormatImpl_EnumType::SharedPointer&);
- ~TypeFormatImpl_EnumType () = default;
+ ~TypeFormatImpl_EnumType ();
ConstString
GetTypeName ()
@@ -301,7 +302,7 @@ namespace lldb_private {
protected:
ConstString m_enum_type;
- mutable std::map<void*,ClangASTType> m_types;
+ mutable std::unordered_map<void*,ClangASTType> m_types;
private:
DISALLOW_COPY_AND_ASSIGN(TypeFormatImpl_EnumType);
diff --git a/include/lldb/DataFormatters/TypeSummary.h b/include/lldb/DataFormatters/TypeSummary.h
index 1c195ab2ba4d..699494336cc6 100644
--- a/include/lldb/DataFormatters/TypeSummary.h
+++ b/include/lldb/DataFormatters/TypeSummary.h
@@ -225,14 +225,14 @@ namespace lldb_private {
return m_flags.GetSkipReferences();
}
- bool
- DoesPrintChildren () const
+ virtual bool
+ DoesPrintChildren (ValueObject* valobj) const
{
return !m_flags.GetDontShowChildren();
}
- bool
- DoesPrintValue () const
+ virtual bool
+ DoesPrintValue (ValueObject* valobj) const
{
return !m_flags.GetDontShowValue();
}
@@ -243,8 +243,8 @@ namespace lldb_private {
return m_flags.GetShowMembersOneLiner();
}
- bool
- HideNames () const
+ virtual bool
+ HideNames (ValueObject* valobj) const
{
return m_flags.GetHideItemNames();
}
@@ -267,13 +267,13 @@ namespace lldb_private {
m_flags.SetSkipReferences(value);
}
- void
+ virtual void
SetDoesPrintChildren (bool value)
{
m_flags.SetDontShowChildren(!value);
}
- void
+ virtual void
SetDoesPrintValue (bool value)
{
m_flags.SetDontShowValue(!value);
@@ -285,7 +285,7 @@ namespace lldb_private {
m_flags.SetShowMembersOneLiner(value);
}
- void
+ virtual void
SetHideNames (bool value)
{
m_flags.SetHideItemNames(value);
diff --git a/include/lldb/DataFormatters/ValueObjectPrinter.h b/include/lldb/DataFormatters/ValueObjectPrinter.h
index 375bb50c876d..bfe2d9c402d3 100644
--- a/include/lldb/DataFormatters/ValueObjectPrinter.h
+++ b/include/lldb/DataFormatters/ValueObjectPrinter.h
@@ -386,7 +386,7 @@ private:
std::string m_summary;
std::string m_error;
- friend class StringSummaryFormat;
+ friend struct StringSummaryFormat;
DISALLOW_COPY_AND_ASSIGN(ValueObjectPrinter);
};
diff --git a/include/lldb/Expression/ASTStructExtractor.h b/include/lldb/Expression/ASTStructExtractor.h
index a1518de83d6d..9e467797a398 100644
--- a/include/lldb/Expression/ASTStructExtractor.h
+++ b/include/lldb/Expression/ASTStructExtractor.h
@@ -30,7 +30,7 @@ namespace lldb_private {
///
/// The definition of this struct is itself in the body of the wrapper function,
/// so Clang does the structure layout itself. ASTStructExtractor reads through
-/// the AST for the wrapper funtion and finds the struct.
+/// the AST for the wrapper function and finds the struct.
//----------------------------------------------------------------------
class ASTStructExtractor : public clang::SemaConsumer
{
diff --git a/include/lldb/Expression/ClangExpressionDeclMap.h b/include/lldb/Expression/ClangExpressionDeclMap.h
index b04e1bd6f116..8a4aa82b8727 100644
--- a/include/lldb/Expression/ClangExpressionDeclMap.h
+++ b/include/lldb/Expression/ClangExpressionDeclMap.h
@@ -167,7 +167,7 @@ public:
const ConstString &name,
llvm::Value *value,
size_t size,
- off_t alignment);
+ lldb::offset_t alignment);
//------------------------------------------------------------------
/// [Used by IRForTarget] Finalize the struct, laying out the position
@@ -198,7 +198,7 @@ public:
bool
GetStructInfo (uint32_t &num_elements,
size_t &size,
- off_t &alignment);
+ lldb::offset_t &alignment);
//------------------------------------------------------------------
/// [Used by IRForTarget] Get specific information about one field
@@ -234,7 +234,7 @@ public:
bool
GetStructElement (const clang::NamedDecl *&decl,
llvm::Value *&value,
- off_t &offset,
+ lldb::offset_t &offset,
ConstString &name,
uint32_t index);
@@ -461,7 +461,7 @@ private:
{
}
- off_t m_struct_alignment; ///< The alignment of the struct in bytes.
+ lldb::offset_t m_struct_alignment; ///< The alignment of the struct in bytes.
size_t m_struct_size; ///< The size of the struct in bytes.
bool m_struct_laid_out; ///< True if the struct has been laid out and the layout is valid (that is, no new fields have been added since).
ConstString m_result_name; ///< The name of the result variable ($1, for example)
diff --git a/include/lldb/Expression/ClangExpressionParser.h b/include/lldb/Expression/ClangExpressionParser.h
index 3247f2094ba6..c79494d1a521 100644
--- a/include/lldb/Expression/ClangExpressionParser.h
+++ b/include/lldb/Expression/ClangExpressionParser.h
@@ -40,7 +40,7 @@ public:
//------------------------------------------------------------------
/// Constructor
///
- /// Initializes class variabes.
+ /// Initializes class variables.
///
/// @param[in] exe_scope,
/// If non-NULL, an execution context scope that can help to
@@ -51,7 +51,8 @@ public:
/// The expression to be parsed.
//------------------------------------------------------------------
ClangExpressionParser (ExecutionContextScope *exe_scope,
- ClangExpression &expr);
+ ClangExpression &expr,
+ bool generate_debug_info);
//------------------------------------------------------------------
/// Destructor
@@ -84,9 +85,9 @@ public:
/// and func_end do not delimit an allocated region; the allocated
/// region may begin before func_addr.)
///
- /// @param[in] execution_unit_ap
+ /// @param[in] execution_unit_sp
/// After parsing, ownership of the execution unit for
- /// for the expression is handed to this unique pointer.
+ /// for the expression is handed to this shared pointer.
///
/// @param[in] exe_ctx
/// The execution context to write the function into.
@@ -112,7 +113,7 @@ public:
Error
PrepareForExecution (lldb::addr_t &func_addr,
lldb::addr_t &func_end,
- std::unique_ptr<IRExecutionUnit> &execution_unit_ap,
+ std::shared_ptr<IRExecutionUnit> &execution_unit_sp,
ExecutionContext &exe_ctx,
bool &can_interpret,
lldb_private::ExecutionPolicy execution_policy);
@@ -134,6 +135,9 @@ public:
DisassembleFunction (Stream &stream,
ExecutionContext &exe_ctx);
+ bool
+ GetGenerateDebugInfo () const;
+
private:
ClangExpression & m_expr; ///< The expression to be parsed
std::unique_ptr<llvm::LLVMContext> m_llvm_context; ///< The LLVM context to generate IR into
@@ -143,7 +147,6 @@ private:
std::unique_ptr<clang::SelectorTable> m_selector_table; ///< Selector table for Objective-C methods
std::unique_ptr<clang::ASTContext> m_ast_context; ///< The AST context used to hold types and names for the parser
std::unique_ptr<clang::CodeGenerator> m_code_generator; ///< The Clang object that generates IR
- std::unique_ptr<IRExecutionUnit> m_execution_unit; ///< The container for the finished Module
};
}
diff --git a/include/lldb/Expression/ClangExpressionVariable.h b/include/lldb/Expression/ClangExpressionVariable.h
index 620e604fb18c..5ee7a3058946 100644
--- a/include/lldb/Expression/ClangExpressionVariable.h
+++ b/include/lldb/Expression/ClangExpressionVariable.h
@@ -162,9 +162,9 @@ public:
{
}
- off_t m_alignment; ///< The required alignment of the variable, in bytes
- size_t m_size; ///< The space required for the variable, in bytes
- off_t m_offset; ///< The offset of the variable in the struct, in bytes
+ lldb::offset_t m_alignment; ///< The required alignment of the variable, in bytes
+ size_t m_size; ///< The space required for the variable, in bytes
+ lldb::offset_t m_offset; ///< The offset of the variable in the struct, in bytes
};
private:
@@ -237,8 +237,8 @@ public:
// this function is used to copy the address-of m_live_sp into m_frozen_sp
// this is necessary because the results of certain cast and pointer-arithmetic
// operations (such as those described in bugzilla issues 11588 and 11618) generate
- // frozen objcts that do not have a valid address-of, which can be troublesome when
- // using synthetic children providers. transferring the address-of the live object
+ // frozen objects that do not have a valid address-of, which can be troublesome when
+ // using synthetic children providers. Transferring the address-of the live object
// solves these issues and provides the expected user-level behavior
void
TransferAddress (bool force = false);
diff --git a/include/lldb/Expression/ClangFunction.h b/include/lldb/Expression/ClangFunction.h
index e150d389b416..61d56729f93d 100644
--- a/include/lldb/Expression/ClangFunction.h
+++ b/include/lldb/Expression/ClangFunction.h
@@ -88,7 +88,8 @@ public:
ClangFunction (ExecutionContextScope &exe_scope,
Function &function_ptr,
ClangASTContext *ast_context,
- const ValueList &arg_value_list);
+ const ValueList &arg_value_list,
+ const char *name);
//------------------------------------------------------------------
/// Constructor
@@ -114,7 +115,8 @@ public:
ClangFunction (ExecutionContextScope &exe_scope,
const ClangASTType &return_type,
const Address& function_address,
- const ValueList &arg_value_list);
+ const ValueList &arg_value_list,
+ const char *name);
//------------------------------------------------------------------
/// Destructor
@@ -251,9 +253,9 @@ public:
/// The result value will be put here after running the function.
///
/// @return
- /// Returns one of the ExecutionResults enum indicating function call status.
+ /// Returns one of the ExpressionResults enum indicating function call status.
//------------------------------------------------------------------
- ExecutionResults
+ lldb::ExpressionResults
ExecuteFunction(ExecutionContext &exe_ctx,
lldb::addr_t *args_addr_ptr,
const EvaluateExpressionOptions &options,
@@ -410,7 +412,9 @@ private:
//------------------------------------------------------------------
std::unique_ptr<ClangExpressionParser> m_parser; ///< The parser responsible for compiling the function.
- std::unique_ptr<IRExecutionUnit> m_execution_unit_ap;
+ std::shared_ptr<IRExecutionUnit> m_execution_unit_sp;
+ lldb::ModuleWP m_jit_module_wp;
+ std::string m_name; ///< The name of this clang function - for debugging purposes.
Function *m_function_ptr; ///< The function we're going to call. May be NULL if we don't have debug info for the function.
Address m_function_addr; ///< If we don't have the FunctionSP, we at least need the address & return type.
diff --git a/include/lldb/Expression/ClangUserExpression.h b/include/lldb/Expression/ClangUserExpression.h
index 83fdf1c21955..9d2e9093c0bd 100644
--- a/include/lldb/Expression/ClangUserExpression.h
+++ b/include/lldb/Expression/ClangUserExpression.h
@@ -105,7 +105,8 @@ public:
Parse (Stream &error_stream,
ExecutionContext &exe_ctx,
lldb_private::ExecutionPolicy execution_policy,
- bool keep_result_in_memory);
+ bool keep_result_in_memory,
+ bool generate_debug_info);
bool
CanInterpret ()
@@ -143,7 +144,7 @@ public:
/// @return
/// A Process::Execution results value.
//------------------------------------------------------------------
- ExecutionResults
+ lldb::ExpressionResults
Execute (Stream &error_stream,
ExecutionContext &exe_ctx,
const EvaluateExpressionOptions& options,
@@ -166,7 +167,7 @@ public:
///
/// @param[in] function_stack_pointer
/// A pointer to the base of the function's stack frame. This
- /// is used to determine whether the expession result resides in
+ /// is used to determine whether the expression result resides in
/// memory that will still be valid, or whether it needs to be
/// treated as homeless for the purpose of future expressions.
///
@@ -295,9 +296,9 @@ public:
/// fails to parse, run, or evaluated.
///
/// @result
- /// A Process::ExecutionResults value. eExecutionCompleted for success.
+ /// A Process::ExpressionResults value. eExpressionCompleted for success.
//------------------------------------------------------------------
- static ExecutionResults
+ static lldb::ExpressionResults
Evaluate (ExecutionContext &exe_ctx,
const EvaluateExpressionOptions& options,
const char *expr_cstr,
@@ -308,7 +309,7 @@ public:
static const Error::ValueType kNoResult = 0x1001; ///< ValueObject::GetError() returns this if there is no result from the expression.
private:
//------------------------------------------------------------------
- /// Populate m_cplusplus and m_objetivec based on the environment.
+ /// Populate m_cplusplus and m_objectivec based on the environment.
//------------------------------------------------------------------
void
@@ -344,11 +345,11 @@ private:
std::string m_transformed_text; ///< The text of the expression, as send to the parser
ResultType m_desired_type; ///< The type to coerce the expression's result to. If eResultTypeAny, inferred from the expression.
- std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing the expression.
- std::unique_ptr<IRExecutionUnit> m_execution_unit_ap; ///< The execution unit the expression is stored in.
- std::unique_ptr<Materializer> m_materializer_ap; ///< The materializer to use when running the expression.
- std::unique_ptr<ASTResultSynthesizer> m_result_synthesizer; ///< The result synthesizer, if one is needed.
-
+ std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing the expression.
+ std::shared_ptr<IRExecutionUnit> m_execution_unit_sp; ///< The execution unit the expression is stored in.
+ std::unique_ptr<Materializer> m_materializer_ap; ///< The materializer to use when running the expression.
+ std::unique_ptr<ASTResultSynthesizer> m_result_synthesizer; ///< The result synthesizer, if one is needed.
+ lldb::ModuleWP m_jit_module_wp;
bool m_enforce_valid_object; ///< True if the expression parser should enforce the presence of a valid class pointer in order to generate the expression as a method.
bool m_cplusplus; ///< True if the expression is compiled as a C++ member function (true if it was parsed when exe_ctx was in a C++ method).
bool m_objectivec; ///< True if the expression is compiled as an Objective-C method (true if it was parsed when exe_ctx was in an Objective-C method).
diff --git a/include/lldb/Expression/ClangUtilityFunction.h b/include/lldb/Expression/ClangUtilityFunction.h
index 6da8e5ec3a8b..bb5601fa2914 100644
--- a/include/lldb/Expression/ClangUtilityFunction.h
+++ b/include/lldb/Expression/ClangUtilityFunction.h
@@ -168,10 +168,10 @@ public:
private:
std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing and materializing the expression.
- std::unique_ptr<IRExecutionUnit> m_execution_unit_ap;
-
- std::string m_function_text; ///< The text of the function. Must be a well-formed translation unit.
- std::string m_function_name; ///< The name of the function.
+ std::shared_ptr<IRExecutionUnit> m_execution_unit_sp;
+ lldb::ModuleWP m_jit_module_wp;
+ std::string m_function_text; ///< The text of the function. Must be a well-formed translation unit.
+ std::string m_function_name; ///< The name of the function.
};
} // namespace lldb_private
diff --git a/include/lldb/Expression/DWARFExpression.h b/include/lldb/Expression/DWARFExpression.h
index 5ecdf7fe9ee5..9ddecc053e00 100644
--- a/include/lldb/Expression/DWARFExpression.h
+++ b/include/lldb/Expression/DWARFExpression.h
@@ -222,6 +222,17 @@ public:
lldb::offset_t data_offset,
lldb::offset_t data_length);
+ void
+ CopyOpcodeData (const void *data,
+ lldb::offset_t data_length,
+ lldb::ByteOrder byte_order,
+ uint8_t addr_byte_size);
+
+ void
+ CopyOpcodeData (uint64_t const_value,
+ lldb::offset_t const_value_byte_size,
+ uint8_t addr_byte_size);
+
//------------------------------------------------------------------
/// Tells the expression that it refers to a location list.
@@ -347,7 +358,7 @@ public:
const DataExtractor& opcodes,
const lldb::offset_t offset,
const lldb::offset_t length,
- const uint32_t reg_set,
+ const lldb::RegisterKind reg_set,
const Value* initial_value_ptr,
Value& result,
Error *error_ptr);
diff --git a/include/lldb/Expression/ExpressionSourceCode.h b/include/lldb/Expression/ExpressionSourceCode.h
index be1014ae3047..2dd09378fcd2 100644
--- a/include/lldb/Expression/ExpressionSourceCode.h
+++ b/include/lldb/Expression/ExpressionSourceCode.h
@@ -17,6 +17,8 @@
namespace lldb_private
{
+class ExecutionContext;
+
class ExpressionSourceCode
{
public:
@@ -53,7 +55,8 @@ public:
bool GetText (std::string &text,
lldb::LanguageType wrapping_language,
bool const_object,
- bool static_method) const;
+ bool static_method,
+ ExecutionContext &exe_ctx) const;
private:
ExpressionSourceCode (const char *name,
diff --git a/include/lldb/Expression/IRExecutionUnit.h b/include/lldb/Expression/IRExecutionUnit.h
index 2820317e108e..3f28351a6928 100644
--- a/include/lldb/Expression/IRExecutionUnit.h
+++ b/include/lldb/Expression/IRExecutionUnit.h
@@ -30,6 +30,7 @@
#include "lldb/Expression/ClangExpressionParser.h"
#include "lldb/Expression/IRMemoryMap.h"
#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/ObjectFile.h"
namespace llvm {
@@ -60,7 +61,10 @@ class Error;
/// into the target process, the IRExecutionUnit knows how to copy the
/// emitted code into the target process.
//----------------------------------------------------------------------
-class IRExecutionUnit : public IRMemoryMap
+class IRExecutionUnit :
+ public std::enable_shared_from_this<IRExecutionUnit>,
+ public IRMemoryMap,
+ public ObjectFileJITDelegate
{
public:
//------------------------------------------------------------------
@@ -77,12 +81,14 @@ public:
//------------------------------------------------------------------
~IRExecutionUnit();
- llvm::Module *GetModule()
+ llvm::Module *
+ GetModule()
{
return m_module;
}
- llvm::Function *GetFunction()
+ llvm::Function *
+ GetFunction()
{
if (m_module)
return m_module->getFunction (m_name.AsCString());
@@ -90,9 +96,10 @@ public:
return NULL;
}
- void GetRunnableInfo(Error &error,
- lldb::addr_t &func_addr,
- lldb::addr_t &func_end);
+ void
+ GetRunnableInfo (Error &error,
+ lldb::addr_t &func_addr,
+ lldb::addr_t &func_end);
//------------------------------------------------------------------
/// Accessors for IRForTarget and other clients that may want binary
@@ -100,11 +107,36 @@ public:
/// IRExecutionUnit unless the client explicitly chooses to free it.
//------------------------------------------------------------------
- lldb::addr_t WriteNow(const uint8_t *bytes,
- size_t size,
- Error &error);
+ lldb::addr_t
+ WriteNow (const uint8_t *bytes,
+ size_t size,
+ Error &error);
+
+ void
+ FreeNow (lldb::addr_t allocation);
+
+ //------------------------------------------------------------------
+ /// ObjectFileJITDelegate overrides
+ //------------------------------------------------------------------
+ virtual lldb::ByteOrder
+ GetByteOrder () const;
- void FreeNow(lldb::addr_t allocation);
+ virtual uint32_t
+ GetAddressByteSize () const;
+
+ virtual void
+ PopulateSymtab (lldb_private::ObjectFile *obj_file,
+ lldb_private::Symtab &symtab);
+
+ virtual void
+ PopulateSectionList (lldb_private::ObjectFile *obj_file,
+ lldb_private::SectionList &section_list);
+
+ virtual bool
+ GetArchitecture (lldb_private::ArchSpec &arch);
+
+ lldb::ModuleSP
+ GetJITModule ();
private:
//------------------------------------------------------------------
@@ -180,6 +212,7 @@ private:
public:
MemoryManager (IRExecutionUnit &parent);
+ virtual ~MemoryManager();
//------------------------------------------------------------------
/// Passthrough interface stub
//------------------------------------------------------------------
@@ -423,7 +456,7 @@ private:
//------------------------------------------------------------------
/// Constructor
///
- /// Initializes class variabes.
+ /// Initializes class variables.
///
/// @param[in] name
/// The name of the function.
@@ -450,31 +483,47 @@ private:
//----------------------------------------------------------------------
/// @class AllocationRecord IRExecutionUnit.h "lldb/Expression/IRExecutionUnit.h"
- /// @brief Enacpsulates a single allocation request made by the JIT.
+ /// @brief Encapsulates a single allocation request made by the JIT.
///
/// Allocations made by the JIT are first queued up and then applied in
/// bulk to the underlying process.
//----------------------------------------------------------------------
+ enum class AllocationKind {
+ Stub, Code, Data, Global, Bytes
+ };
+
+ static lldb::SectionType
+ GetSectionTypeFromSectionName (const llvm::StringRef &name,
+ AllocationKind alloc_kind);
+
struct AllocationRecord {
- lldb::addr_t m_process_address;
- uintptr_t m_host_address;
- uint32_t m_permissions;
- size_t m_size;
- unsigned m_alignment;
- unsigned m_section_id;
+ std::string m_name;
+ lldb::addr_t m_process_address;
+ uintptr_t m_host_address;
+ uint32_t m_permissions;
+ lldb::SectionType m_sect_type;
+ size_t m_size;
+ unsigned m_alignment;
+ unsigned m_section_id;
AllocationRecord (uintptr_t host_address,
uint32_t permissions,
+ lldb::SectionType sect_type,
size_t size,
unsigned alignment,
- unsigned section_id = eSectionIDInvalid) :
+ unsigned section_id,
+ const char *name) :
+ m_name (),
m_process_address(LLDB_INVALID_ADDRESS),
m_host_address(host_address),
m_permissions(permissions),
+ m_sect_type (sect_type),
m_size(size),
m_alignment(alignment),
m_section_id(section_id)
{
+ if (name && name[0])
+ m_name = name;
}
void dump (Log *log);
diff --git a/include/lldb/Expression/IRForTarget.h b/include/lldb/Expression/IRForTarget.h
index 502f796d15a1..0ad34904f563 100644
--- a/include/lldb/Expression/IRForTarget.h
+++ b/include/lldb/Expression/IRForTarget.h
@@ -61,6 +61,12 @@ namespace lldb_private {
class IRForTarget : public llvm::ModulePass
{
public:
+ enum class LookupResult {
+ Success,
+ Fail,
+ Ignore
+ };
+
//------------------------------------------------------------------
/// Constructor
///
@@ -182,7 +188,7 @@ private:
//------------------------------------------------------------------
//------------------------------------------------------------------
- /// Get the address of a fuction, and a location to put the complete
+ /// Get the address of a function, and a location to put the complete
/// Value of the function if one is available.
///
/// @param[in] function
@@ -201,7 +207,7 @@ private:
/// @return
/// The pointer.
//------------------------------------------------------------------
- bool
+ LookupResult
GetFunctionAddress (llvm::Function *function,
uint64_t &ptr,
lldb_private::ConstString &name,
@@ -573,7 +579,7 @@ private:
ReplaceStrings ();
//------------------------------------------------------------------
- /// A basick block-level pass to find all literals that will be
+ /// A basic block-level pass to find all literals that will be
/// allocated as statics by the JIT (in contrast to the Strings,
/// which already are statics) and synthesize loads for them.
//------------------------------------------------------------------
diff --git a/include/lldb/Expression/IRMemoryMap.h b/include/lldb/Expression/IRMemoryMap.h
index affe19350e3f..4faa5226d9b4 100644
--- a/include/lldb/Expression/IRMemoryMap.h
+++ b/include/lldb/Expression/IRMemoryMap.h
@@ -27,7 +27,8 @@ namespace lldb_private
/// This class encapsulates a group of memory objects that must be readable
/// or writable from the host process regardless of whether the process
/// exists. This allows the IR interpreter as well as JITted code to access
-/// the same memory.
+/// the same memory. All allocations made by this class are represented as
+/// disjoint intervals.
///
/// Point queries against this group of memory objects can be made by the
/// address in the tar at which they reside. If the inferior does not
@@ -66,7 +67,7 @@ public:
uint32_t GetAddressByteSize();
// This function can return NULL.
- ExecutionContextScope *GetBestExecutionContextScope();
+ ExecutionContextScope *GetBestExecutionContextScope() const;
protected:
// This function should only be used if you know you are using the JIT.
@@ -118,7 +119,12 @@ private:
lldb::addr_t FindSpace (size_t size);
bool ContainsHostOnlyAllocations ();
AllocationMap::iterator FindAllocation (lldb::addr_t addr, size_t size);
- bool IntersectsAllocation (lldb::addr_t addr, size_t size);
+
+ // Returns true if the given allocation intersects any allocation in the memory map.
+ bool IntersectsAllocation (lldb::addr_t addr, size_t size) const;
+
+ // Returns true if the two given allocations intersect each other.
+ static bool AllocationsIntersect (lldb::addr_t addr1, size_t size1, lldb::addr_t addr2, size_t size2);
};
}
diff --git a/include/lldb/Host/Condition.h b/include/lldb/Host/Condition.h
index 2f1858b75a56..7431315c37a0 100644
--- a/include/lldb/Host/Condition.h
+++ b/include/lldb/Host/Condition.h
@@ -25,7 +25,7 @@ class TimeValue;
///
/// A class that wraps up a pthread condition (pthread_cond_t). The
/// class will create a pthread condition when an instance is
-/// constructed, and detroy it when it is destructed. It also provides
+/// constructed, and destroy it when it is destructed. It also provides
/// access to the standard pthread condition calls.
//----------------------------------------------------------------------
class Condition
diff --git a/include/lldb/Host/Config.h b/include/lldb/Host/Config.h
index 80616b747cf5..af6b98a7912a 100644
--- a/include/lldb/Host/Config.h
+++ b/include/lldb/Host/Config.h
@@ -18,7 +18,7 @@
#include "lldb/Host/linux/Config.h"
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__)
#include "lldb/Host/freebsd/Config.h"
diff --git a/include/lldb/Host/Debug.h b/include/lldb/Host/Debug.h
index 2cb758e1b733..87dffb9865c2 100644
--- a/include/lldb/Host/Debug.h
+++ b/include/lldb/Host/Debug.h
@@ -10,14 +10,11 @@
#ifndef liblldb_Debug_h_
#define liblldb_Debug_h_
-#include "lldb/lldb-private.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/Mutex.h"
#include <vector>
+#include "lldb/lldb-private.h"
namespace lldb_private {
-
+
//------------------------------------------------------------------
// Tells a thread what it needs to do when the process is resumed.
//------------------------------------------------------------------
@@ -27,7 +24,7 @@ namespace lldb_private {
lldb::StateType state; // Valid values are eStateStopped/eStateSuspended, eStateRunning, and eStateStepping.
int signal; // When resuming this thread, resume it with this signal if this value is > 0
};
-
+
//------------------------------------------------------------------
// A class that contains instructions for all threads for
// NativeProcessProtocol::Resume(). Each thread can either run, stay
@@ -43,15 +40,14 @@ namespace lldb_private {
m_signal_handled ()
{
}
-
+
ResumeActionList (lldb::StateType default_action, int signal) :
m_actions(),
m_signal_handled ()
{
SetDefaultThreadActionIfNeeded (default_action, signal);
}
-
-
+
ResumeActionList (const ResumeAction *actions, size_t num_actions) :
m_actions (),
m_signal_handled ()
@@ -62,7 +58,7 @@ namespace lldb_private {
m_signal_handled.assign (num_actions, false);
}
}
-
+
~ResumeActionList()
{
}
@@ -72,14 +68,14 @@ namespace lldb_private {
{
return m_actions.empty();
}
-
+
void
Append (const ResumeAction &action)
{
m_actions.push_back (action);
m_signal_handled.push_back (false);
}
-
+
void
AppendAction (lldb::tid_t tid,
lldb::StateType state,
@@ -88,25 +84,25 @@ namespace lldb_private {
ResumeAction action = { tid, state, signal };
Append (action);
}
-
+
void
AppendResumeAll ()
{
AppendAction (LLDB_INVALID_THREAD_ID, lldb::eStateRunning);
}
-
+
void
AppendSuspendAll ()
{
AppendAction (LLDB_INVALID_THREAD_ID, lldb::eStateStopped);
}
-
+
void
AppendStepAll ()
{
AppendAction (LLDB_INVALID_THREAD_ID, lldb::eStateStepping);
}
-
+
const ResumeAction *
GetActionForThread (lldb::tid_t tid, bool default_ok) const
{
@@ -120,7 +116,7 @@ namespace lldb_private {
return GetActionForThread (LLDB_INVALID_THREAD_ID, false);
return NULL;
}
-
+
size_t
NumActionsWithState (lldb::StateType state) const
{
@@ -133,7 +129,7 @@ namespace lldb_private {
}
return count;
}
-
+
bool
SetDefaultThreadActionIfNeeded (lldb::StateType action, int signal)
{
@@ -147,7 +143,7 @@ namespace lldb_private {
}
return false;
}
-
+
void
SetSignalHandledForThread (lldb::tid_t tid) const
{
@@ -161,26 +157,26 @@ namespace lldb_private {
}
}
}
-
+
const ResumeAction *
GetFirst() const
{
return m_actions.data();
}
-
+
size_t
GetSize () const
{
return m_actions.size();
}
-
+
void
Clear()
{
m_actions.clear();
m_signal_handled.clear();
}
-
+
protected:
std::vector<ResumeAction> m_actions;
mutable std::vector<bool> m_signal_handled;
@@ -191,13 +187,13 @@ namespace lldb_private {
lldb::StopReason reason;
union
{
- // eStopTypeSignal
+ // eStopReasonSignal
struct
{
uint32_t signo;
} signal;
-
- // eStopTypeException
+
+ // eStopReasonException
struct
{
uint64_t type;
@@ -206,201 +202,5 @@ namespace lldb_private {
} exception;
} details;
};
-
- //------------------------------------------------------------------
- // NativeThreadProtocol
- //------------------------------------------------------------------
- class NativeThreadProtocol {
-
- public:
- NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid) :
- m_process (process),
- m_tid (tid)
- {
- }
-
- virtual ~NativeThreadProtocol()
- {
- }
- virtual const char *GetName() = 0;
- virtual lldb::StateType GetState () = 0;
- virtual Error ReadRegister (uint32_t reg, RegisterValue &reg_value) = 0;
- virtual Error WriteRegister (uint32_t reg, const RegisterValue &reg_value) = 0;
- virtual Error SaveAllRegisters (lldb::DataBufferSP &data_sp) = 0;
- virtual Error RestoreAllRegisters (lldb::DataBufferSP &data_sp) = 0;
- virtual bool GetStopReason (ThreadStopInfo &stop_info) = 0;
-
- lldb::tid_t
- GetID() const
- {
- return m_tid;
- }
- protected:
- NativeProcessProtocol *m_process;
- lldb::tid_t m_tid;
- };
-
-
- //------------------------------------------------------------------
- // NativeProcessProtocol
- //------------------------------------------------------------------
- class NativeProcessProtocol {
- public:
-
- static NativeProcessProtocol *
- CreateInstance (lldb::pid_t pid);
-
- // lldb_private::Host calls should be used to launch a process for debugging, and
- // then the process should be attached to. When attaching to a process
- // lldb_private::Host calls should be used to locate the process to attach to,
- // and then this function should be called.
- NativeProcessProtocol (lldb::pid_t pid) :
- m_pid (pid),
- m_threads(),
- m_threads_mutex (Mutex::eMutexTypeRecursive),
- m_state (lldb::eStateInvalid),
- m_exit_status(0),
- m_exit_description()
- {
- }
-
- public:
- virtual ~NativeProcessProtocol ()
- {
- }
-
- virtual Error Resume (const ResumeActionList &resume_actions) = 0;
- virtual Error Halt () = 0;
- virtual Error Detach () = 0;
- virtual Error Signal (int signo) = 0;
- virtual Error Kill () = 0;
-
- virtual Error ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read) = 0;
- virtual Error WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written) = 0;
- virtual Error AllocateMemory (lldb::addr_t size, uint32_t permissions, lldb::addr_t &addr) = 0;
- virtual Error DeallocateMemory (lldb::addr_t addr) = 0;
-
- virtual lldb::addr_t GetSharedLibraryInfoAddress () = 0;
-
- virtual bool IsAlive () = 0;
- virtual size_t UpdateThreads () = 0;
- virtual bool GetArchitecture (ArchSpec &arch) = 0;
-
- //----------------------------------------------------------------------
- // Breakpoint functions
- //----------------------------------------------------------------------
- virtual Error SetBreakpoint (lldb::addr_t addr, size_t size, bool hardware) = 0;
- virtual Error RemoveBreakpoint (lldb::addr_t addr, size_t size) = 0;
-
- //----------------------------------------------------------------------
- // Watchpoint functions
- //----------------------------------------------------------------------
- virtual uint32_t GetMaxWatchpoints () = 0;
- virtual Error SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) = 0;
- virtual Error RemoveWatchpoint (lldb::addr_t addr) = 0;
-
-
- //----------------------------------------------------------------------
- // Accessors
- //----------------------------------------------------------------------
- lldb::pid_t
- GetID() const
- {
- return m_pid;
- }
-
- lldb::StateType
- GetState () const
- {
- return m_state;
- }
-
- bool
- IsRunning () const
- {
- return m_state == lldb::eStateRunning || IsStepping();
- }
-
- bool
- IsStepping () const
- {
- return m_state == lldb::eStateStepping;
- }
-
- bool
- CanResume () const
- {
- return m_state == lldb::eStateStopped;
- }
-
-
- void
- SetState (lldb::StateType state)
- {
- m_state = state;
- }
-
- //----------------------------------------------------------------------
- // Exit Status
- //----------------------------------------------------------------------
- virtual bool
- GetExitStatus (int *status)
- {
- if (m_state == lldb::eStateExited)
- {
- *status = m_exit_status;
- return true;
- }
- *status = 0;
- return false;
- }
- virtual bool
- SetExitStatus (int status, const char *exit_description)
- {
- // Exit status already set
- if (m_state == lldb::eStateExited)
- return false;
- m_state = lldb::eStateExited;
- m_exit_status = status;
- if (exit_description && exit_description[0])
- m_exit_description = exit_description;
- else
- m_exit_description.clear();
- return true;
- }
-
- //----------------------------------------------------------------------
- // Access to threads
- //----------------------------------------------------------------------
- lldb::NativeThreadProtocolSP
- GetThreadAtIndex (uint32_t idx)
- {
- Mutex::Locker locker(m_threads_mutex);
- if (idx < m_threads.size())
- return m_threads[idx];
- return lldb::NativeThreadProtocolSP();
- }
-
- lldb::NativeThreadProtocolSP
- GetThreadByID (lldb::tid_t tid)
- {
- Mutex::Locker locker(m_threads_mutex);
- for (auto thread_sp : m_threads)
- {
- if (thread_sp->GetID() == tid)
- return thread_sp;
- }
- return lldb::NativeThreadProtocolSP();
- }
-
- protected:
- lldb::pid_t m_pid;
- std::vector<lldb::NativeThreadProtocolSP> m_threads;
- mutable Mutex m_threads_mutex;
- lldb::StateType m_state;
- int m_exit_status;
- std::string m_exit_description;
- };
-
}
#endif // #ifndef liblldb_Debug_h_
diff --git a/include/lldb/Host/DynamicLibrary.h b/include/lldb/Host/DynamicLibrary.h
deleted file mode 100644
index 1fcc7d1883cf..000000000000
--- a/include/lldb/Host/DynamicLibrary.h
+++ /dev/null
@@ -1,51 +0,0 @@
-//===-- DynamicLibrary.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_DynamicLibrary_h_
-#define liblldb_DynamicLibrary_h_
-
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/Host.h"
-
-namespace lldb_private {
-
-class DynamicLibrary
-{
-public:
- DynamicLibrary (const FileSpec& spec, uint32_t options = Host::eDynamicLibraryOpenOptionLazy |
- Host::eDynamicLibraryOpenOptionLocal |
- Host::eDynamicLibraryOpenOptionLimitGetSymbol);
-
- ~DynamicLibrary ();
-
- template <typename T = void*>
- T GetSymbol (const char* name)
- {
- Error err;
- if (!m_handle)
- return (T)NULL;
- void* symbol = Host::DynamicLibraryGetSymbol (m_handle, name, err);
- if (!symbol)
- return (T)NULL;
- return (T)symbol;
- }
-
- bool
- IsValid ();
-
-private:
- lldb_private::FileSpec m_filespec;
- void* m_handle;
-
- DISALLOW_COPY_AND_ASSIGN (DynamicLibrary);
-};
-
-} // namespace lldb_private
-
-#endif // liblldb_DynamicLibrary_h_
diff --git a/include/lldb/Host/Editline.h b/include/lldb/Host/Editline.h
index b92de1052f29..5cba8465d654 100644
--- a/include/lldb/Host/Editline.h
+++ b/include/lldb/Host/Editline.h
@@ -23,9 +23,11 @@
#include <string>
#include <vector>
+#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Host/Condition.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Predicate.h"
namespace lldb_private {
@@ -33,6 +35,10 @@ namespace lldb_private {
/// @class Editline Editline.h "lldb/Host/Editline.h"
/// @brief A class that encapsulates editline functionality.
//----------------------------------------------------------------------
+class EditlineHistory;
+
+typedef std::shared_ptr<EditlineHistory> EditlineHistorySP;
+
class Editline
{
public:
@@ -58,6 +64,7 @@ public:
Editline(const char *prog, // Used for the history file and for editrc program name
const char *prompt,
+ bool configure_for_multiline,
FILE *fin,
FILE *fout,
FILE *ferr);
@@ -65,10 +72,13 @@ public:
~Editline();
Error
- GetLine (std::string &line);
+ GetLine (std::string &line,
+ bool &interrupted);
Error
- GetLines (const std::string &end_line, StringList &lines);
+ GetLines (const std::string &end_line,
+ StringList &lines,
+ bool &interrupted);
bool
LoadHistory ();
@@ -97,7 +107,7 @@ public:
void
Refresh();
- void
+ bool
Interrupt ();
void
@@ -118,11 +128,6 @@ public:
size_t
Push (const char *bytes, size_t len);
-
- // Cache bytes and use them for input without using a FILE. Calling this function
- // will set the getc callback in the editline
- size_t
- SetInputBuffer (const char *c, size_t len);
static int
GetCharFromInputFileCallback (::EditLine *e, char *c);
@@ -135,21 +140,21 @@ public:
void
SetPrompt (const char *p);
-
+
+ void
+ ShowLineNumbers (bool enable, uint32_t line_offset)
+ {
+ m_prompt_with_line_numbers = enable;
+ m_line_offset = line_offset;
+ }
+
private:
Error
PrivateGetLine(std::string &line);
- FileSpec
- GetHistoryFile();
-
unsigned char
HandleCompletion (int ch);
-
- int
- GetChar (char *c);
-
static unsigned char
CallbackEditPrevLine (::EditLine *e, int ch);
@@ -169,9 +174,6 @@ private:
static FILE *
GetFilePointer (::EditLine *e, int fd);
- static int
- GetCharInputBufferCallback (::EditLine *e, char *c);
-
enum class Command
{
None = 0,
@@ -179,22 +181,19 @@ private:
EditNextLine,
};
::EditLine *m_editline;
- ::History *m_history;
- ::HistEvent m_history_event;
- std::string m_program;
+ EditlineHistorySP m_history_sp;
std::string m_prompt;
std::string m_lines_prompt;
- std::string m_getc_buffer;
- Mutex m_getc_mutex;
- Condition m_getc_cond;
+ lldb_private::Predicate<bool> m_getting_char;
CompleteCallbackType m_completion_callback;
void *m_completion_callback_baton;
-// Mutex m_gets_mutex; // Make sure only one thread
LineCompletedCallbackType m_line_complete_callback;
void *m_line_complete_callback_baton;
Command m_lines_command;
+ uint32_t m_line_offset;
uint32_t m_lines_curr_line;
uint32_t m_lines_max_line;
+ ConnectionFileDescriptor m_file;
bool m_prompt_with_line_numbers;
bool m_getting_line;
bool m_got_eof; // Set to true when we detect EOF
diff --git a/include/lldb/Host/Endian.h b/include/lldb/Host/Endian.h
index 610f3ce95c41..1ae3c40b5ca4 100644
--- a/include/lldb/Host/Endian.h
+++ b/include/lldb/Host/Endian.h
@@ -20,7 +20,7 @@ namespace endian {
{
uint32_t num;
uint8_t bytes[sizeof(uint32_t)];
- } const endianTest = { (uint16_t)0x01020304 };
+ } const endianTest = { 0x01020304 };
inline ByteOrder InlHostByteOrder() { return (ByteOrder)endianTest.bytes[0]; }
diff --git a/include/lldb/Host/File.h b/include/lldb/Host/File.h
index 814d96059f37..2738679b5e03 100644
--- a/include/lldb/Host/File.h
+++ b/include/lldb/Host/File.h
@@ -16,6 +16,7 @@
#include <sys/types.h>
#include "lldb/lldb-private.h"
+#include "lldb/Host/IOObject.h"
namespace lldb_private {
@@ -26,7 +27,7 @@ namespace lldb_private {
/// A file class that divides abstracts the LLDB core from host file
/// functionality.
//----------------------------------------------------------------------
-class File
+class File : public IOObject
{
public:
static int kInvalidDescriptor;
@@ -48,22 +49,22 @@ public:
ConvertOpenOptionsForPOSIXOpen (uint32_t open_options);
File() :
+ IOObject(eFDTypeFile, false),
m_descriptor (kInvalidDescriptor),
m_stream (kInvalidStream),
m_options (0),
m_own_stream (false),
- m_own_descriptor (false),
m_is_interactive (eLazyBoolCalculate),
m_is_real_terminal (eLazyBoolCalculate)
{
}
File (FILE *fh, bool transfer_ownership) :
+ IOObject(eFDTypeFile, false),
m_descriptor (kInvalidDescriptor),
m_stream (fh),
m_options (0),
m_own_stream (transfer_ownership),
- m_own_descriptor (false),
m_is_interactive (eLazyBoolCalculate),
m_is_real_terminal (eLazyBoolCalculate)
{
@@ -118,11 +119,11 @@ public:
uint32_t permissions = lldb::eFilePermissionsFileDefault);
File (int fd, bool transfer_ownership) :
+ IOObject(eFDTypeFile, transfer_ownership),
m_descriptor (fd),
m_stream (kInvalidStream),
m_options (0),
- m_own_stream (false),
- m_own_descriptor (transfer_ownership)
+ m_own_stream (false)
{
}
@@ -222,6 +223,10 @@ public:
int
GetDescriptor() const;
+ WaitableHandle
+ GetWaitableHandle();
+
+
void
SetDescriptor(int fd, bool transfer_ownership);
@@ -331,7 +336,7 @@ public:
///
/// @param[in/out] offset
/// The offset to seek to within the file relative to the
- /// end of the file which gets filled in the the resulting
+ /// end of the file which gets filled in with the resulting
/// absolute file offset.
///
/// @param[in] error_ptr
@@ -482,7 +487,7 @@ public:
///
/// Just knowing a file is a interactive isn't enough, we also need
/// to know if the terminal has a width and height so we can do
- /// cursor movement and other terminal maninpulations by sending
+ /// cursor movement and other terminal manipulations by sending
/// escape sequences.
///
/// @return
@@ -541,7 +546,6 @@ protected:
FILE *m_stream;
uint32_t m_options;
bool m_own_stream;
- bool m_own_descriptor;
LazyBool m_is_interactive;
LazyBool m_is_real_terminal;
};
diff --git a/include/lldb/Host/FileCache.h b/include/lldb/Host/FileCache.h
new file mode 100644
index 000000000000..779ff983de98
--- /dev/null
+++ b/include/lldb/Host/FileCache.h
@@ -0,0 +1,45 @@
+//===-- FileCache.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_Host_FileCache_h
+#define liblldb_Host_FileCache_h
+
+#include <stdint.h>
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Host/FileSpec.h"
+
+namespace lldb_private
+{
+class FileCache
+{
+ private:
+ FileCache() {}
+
+ typedef std::map<lldb::user_id_t, lldb::FileSP> FDToFileMap;
+
+ public:
+ static FileCache &GetInstance();
+
+ lldb::user_id_t OpenFile(const FileSpec &file_spec, uint32_t flags, uint32_t mode, Error &error);
+ bool CloseFile(lldb::user_id_t fd, Error &error);
+
+ uint64_t WriteFile(lldb::user_id_t fd, uint64_t offset, const void *src, uint64_t src_len, Error &error);
+ uint64_t ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, Error &error);
+
+ private:
+ static FileCache *m_instance;
+
+ FDToFileMap m_cache;
+};
+}
+
+#endif
diff --git a/include/lldb/Host/FileSpec.h b/include/lldb/Host/FileSpec.h
index dfc4e4ae0fe3..ef73bb2ede0f 100644
--- a/include/lldb/Host/FileSpec.h
+++ b/include/lldb/Host/FileSpec.h
@@ -51,6 +51,13 @@ public:
eFileTypeOther
} FileType;
+ enum PathSyntax
+ {
+ ePathSyntaxPosix,
+ ePathSyntaxWindows,
+ ePathSyntaxHostNative
+ };
+
FileSpec();
//------------------------------------------------------------------
@@ -69,7 +76,7 @@ public:
///
/// @see FileSpec::SetFile (const char *path, bool resolve)
//------------------------------------------------------------------
- explicit FileSpec (const char *path, bool resolve_path);
+ explicit FileSpec (const char *path, bool resolve_path, PathSyntax syntax = ePathSyntaxHostNative);
//------------------------------------------------------------------
/// Copy constructor
@@ -249,7 +256,7 @@ public:
/// by a directory delimiter, and the filename.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
//------------------------------------------------------------------
void
Dump (Stream *s) const;
@@ -263,6 +270,15 @@ public:
bool
Exists () const;
+ //------------------------------------------------------------------
+ /// Check if a file is readable by the current user
+ ///
+ /// @return
+ /// \b true if the file exists on disk and is readable, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ Readable () const;
//------------------------------------------------------------------
/// Expanded existence test.
@@ -291,6 +307,9 @@ public:
uint64_t
GetByteSize() const;
+ PathSyntax
+ GetPathSyntax() const;
+
//------------------------------------------------------------------
/// Directory string get accessor.
///
@@ -375,7 +394,7 @@ public:
/// still NULL terminated).
//------------------------------------------------------------------
size_t
- GetPath (char *path, size_t max_path_length) const;
+ GetPath (char *path, size_t max_path_length, bool denormalize = true) const;
//------------------------------------------------------------------
/// Extract the full path to the file.
@@ -387,7 +406,7 @@ public:
/// concatenated.
//------------------------------------------------------------------
std::string
- GetPath () const;
+ GetPath (bool denormalize = true) const;
//------------------------------------------------------------------
/// Extract the extension of the file.
@@ -486,7 +505,7 @@ public:
/// Returns a shared pointer to a data buffer that contains all or
/// part of the contents of a file. The data is memory mapped and
/// will lazily page in data from the file as memory is accessed.
- /// The data that is mappped will start \a offset bytes into the
+ /// The data that is mapped will start \a offset bytes into the
/// file, and \a length bytes will be mapped. If \a length is
/// greater than the number of bytes available in the file starting
/// at \a offset, the number of bytes will be appropriately
@@ -504,7 +523,7 @@ public:
/// as many bytes as possible.
///
/// @return
- /// A shared pointer to the memeory mapped data. This shared
+ /// A shared pointer to the memory mapped data. This shared
/// pointer can contain a NULL DataBuffer pointer, so the contained
/// pointer must be checked prior to using it.
//------------------------------------------------------------------
@@ -559,8 +578,12 @@ public:
//------------------------------------------------------------------
lldb::DataBufferSP
ReadFileContentsAsCString(Error *error_ptr = NULL);
+
+ static void Normalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax = ePathSyntaxHostNative);
+ static void DeNormalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax = ePathSyntaxHostNative);
+
//------------------------------------------------------------------
- /// Change the file specificed with a new path.
+ /// Change the file specified with a new path.
///
/// Update the contents of this object with a new path. The path will
/// be split up into a directory and filename and stored as uniqued
@@ -574,7 +597,7 @@ public:
/// the static FileSpec::Resolve.
//------------------------------------------------------------------
void
- SetFile (const char *path, bool resolve_path);
+ SetFile (const char *path, bool resolve_path, PathSyntax syntax = ePathSyntaxHostNative);
bool
IsResolved () const
@@ -617,27 +640,14 @@ public:
ReadFileLines (STLStringArray &lines);
//------------------------------------------------------------------
- /// Resolves user name and links in \a src_path, and writes the output
- /// to \a dst_path. Note if the path pointed to by \a src_path does not
- /// exist, the contents of \a src_path will be copied to \a dst_path
- /// unchanged.
+ /// Resolves user name and links in \a path, and overwrites the input
+ /// argument with the resolved path.
///
- /// @param[in] src_path
- /// Input path to be resolved.
- ///
- /// @param[in] dst_path
- /// Buffer to store the resolved path.
- ///
- /// @param[in] dst_len
- /// Size of the buffer pointed to by dst_path.
- ///
- /// @result
- /// The number of characters required to write the resolved path. If the
- /// resolved path doesn't fit in dst_len, dst_len-1 characters will
- /// be written to \a dst_path, but the actual required length will still be returned.
+ /// @param[in] path
+ /// Input path to be resolved, in the form of a llvm::SmallString or similar.
//------------------------------------------------------------------
- static size_t
- Resolve (const char *src_path, char *dst_path, size_t dst_len);
+ static void
+ Resolve (llvm::SmallVectorImpl<char> &path);
FileSpec
CopyByAppendingPathComponent (const char *new_path) const;
@@ -665,18 +675,9 @@ public:
///
/// @param[in] dst_path
/// Buffer to store the resolved path.
- ///
- /// @param[in] dst_len
- /// Size of the buffer pointed to by dst_path.
- ///
- /// @result
- /// The number of characters required to write the resolved path, or 0 if
- /// the user name could not be found. If the
- /// resolved path doesn't fit in dst_len, dst_len-1 characters will
- /// be written to \a dst_path, but the actual required length will still be returned.
//------------------------------------------------------------------
- static size_t
- ResolveUsername (const char *src_path, char *dst_path, size_t dst_len);
+ static void
+ ResolveUsername (llvm::SmallVectorImpl<char> &path);
static size_t
ResolvePartialUsername (const char *partial_name, StringList &matches);
@@ -709,6 +710,7 @@ protected:
ConstString m_directory; ///< The uniqued directory path
ConstString m_filename; ///< The uniqued filename path
mutable bool m_is_resolved; ///< True if this path has been resolved.
+ PathSyntax m_syntax; ///< The syntax that this path uses (e.g. Windows / Posix)
};
//----------------------------------------------------------------------
diff --git a/include/lldb/Host/FileSystem.h b/include/lldb/Host/FileSystem.h
new file mode 100644
index 000000000000..adcbfc9d590d
--- /dev/null
+++ b/include/lldb/Host/FileSystem.h
@@ -0,0 +1,43 @@
+//===-- FileSystem.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_Host_FileSystem_h
+#define liblldb_Host_FileSystem_h
+
+#include <stdint.h>
+
+#include "lldb/lldb-types.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Host/FileSpec.h"
+
+namespace lldb_private
+{
+class FileSystem
+{
+ public:
+ static FileSpec::PathSyntax GetNativePathSyntax();
+
+ static Error MakeDirectory(const char *path, uint32_t mode);
+ static Error DeleteDirectory(const char *path, bool recurse);
+
+ static Error GetFilePermissions(const char *path, uint32_t &file_permissions);
+ static Error SetFilePermissions(const char *path, uint32_t file_permissions);
+ static lldb::user_id_t GetFileSize(const FileSpec &file_spec);
+ static bool GetFileExists(const FileSpec &file_spec);
+
+ static Error Symlink(const char *src, const char *dst);
+ static Error Readlink(const char *path, char *buf, size_t buf_len);
+ static Error Unlink(const char *path);
+
+ static bool CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high);
+};
+}
+
+#endif
diff --git a/include/lldb/Host/Host.h b/include/lldb/Host/Host.h
index 862b1ed79432..19ed7b01e80f 100644
--- a/include/lldb/Host/Host.h
+++ b/include/lldb/Host/Host.h
@@ -17,11 +17,16 @@
#include <string>
#include "lldb/lldb-private.h"
+#include "lldb/lldb-private-forward.h"
#include "lldb/Core/StringList.h"
#include "lldb/Host/File.h"
+#include "lldb/Host/FileSpec.h"
namespace lldb_private {
+class FileAction;
+class ProcessLaunchInfo;
+
//----------------------------------------------------------------------
/// @class Host Host.h "lldb/Host/Host.h"
/// @brief A class that provides host computer information.
@@ -32,6 +37,10 @@ namespace lldb_private {
class Host
{
public:
+
+ /// A value of std::numeric_limits<uint32_t>::max() is used if there is no practical limit.
+ static const uint32_t MAX_THREAD_NAME_LENGTH;
+
typedef bool (*MonitorChildProcessCallback) (void *callback_baton,
lldb::pid_t pid,
bool exited,
@@ -48,11 +57,11 @@ public:
/// thread so the callback function must be thread safe.
///
/// When the callback gets called, the return value indicates if
- /// minotoring should stop. If \b true is returned from \a callback
+ /// monitoring should stop. If \b true is returned from \a callback
/// the information will be removed. If \b false is returned then
/// monitoring will continue. If the child process exits, the
/// monitoring will automatically stop after the callback returned
- /// ragardless of the callback return value.
+ /// regardless of the callback return value.
///
/// @param[in] callback
/// A function callback to call when a child receives a signal
@@ -83,68 +92,6 @@ public:
lldb::pid_t pid,
bool monitor_signals);
- //------------------------------------------------------------------
- /// Get the host page size.
- ///
- /// @return
- /// The size in bytes of a VM page on the host system.
- //------------------------------------------------------------------
- static size_t
- GetPageSize();
-
- //------------------------------------------------------------------
- /// Returns the endianness of the host system.
- ///
- /// @return
- /// Returns the endianness of the host system as a lldb::ByteOrder
- /// enumeration.
- //------------------------------------------------------------------
- static lldb::ByteOrder
- GetByteOrder ();
-
- //------------------------------------------------------------------
- /// Returns the number of CPUs on this current host.
- ///
- /// @return
- /// Number of CPUs on this current host, or zero if the number
- /// of CPUs can't be determined on this host.
- //------------------------------------------------------------------
- static uint32_t
- GetNumberCPUS ();
-
- static bool
- GetOSVersion (uint32_t &major,
- uint32_t &minor,
- uint32_t &update);
-
- static bool
- GetOSBuildString (std::string &s);
-
- static bool
- GetOSKernelDescription (std::string &s);
-
- static bool
- GetHostname (std::string &s);
-
- static const char *
- GetUserName (uint32_t uid, std::string &user_name);
-
- static const char *
- GetGroupName (uint32_t gid, std::string &group_name);
-
- static uint32_t
- GetUserID ();
-
- static uint32_t
- GetGroupID ();
-
- static uint32_t
- GetEffectiveUserID ();
-
- static uint32_t
- GetEffectiveGroupID ();
-
-
enum SystemLogType
{
eSystemLogWarning,
@@ -158,67 +105,6 @@ public:
SystemLog (SystemLogType type, const char *format, va_list args);
//------------------------------------------------------------------
- /// Gets the host architecture.
- ///
- /// @return
- /// A const architecture object that represents the host
- /// architecture.
- //------------------------------------------------------------------
- enum SystemDefaultArchitecture
- {
- eSystemDefaultArchitecture, // The overall default architecture that applications will run on this host
- eSystemDefaultArchitecture32, // If this host supports 32 bit programs, return the default 32 bit arch
- eSystemDefaultArchitecture64 // If this host supports 64 bit programs, return the default 64 bit arch
- };
-
- static const ArchSpec &
- GetArchitecture (SystemDefaultArchitecture arch_kind = eSystemDefaultArchitecture);
-
- //------------------------------------------------------------------
- /// Gets the host vendor string.
- ///
- /// @return
- /// A const string object containing the host vendor name.
- //------------------------------------------------------------------
- static const ConstString &
- GetVendorString ();
-
- //------------------------------------------------------------------
- /// Gets the host Operating System (OS) string.
- ///
- /// @return
- /// A const string object containing the host OS name.
- //------------------------------------------------------------------
- static const ConstString &
- GetOSString ();
-
- //------------------------------------------------------------------
- /// Gets the host target triple as a const string.
- ///
- /// @return
- /// A const string object containing the host target triple.
- //------------------------------------------------------------------
- static const ConstString &
- GetTargetTriple ();
-
- //------------------------------------------------------------------
- /// Gets the name of the distribution (i.e. distributor id).
- ///
- /// On Linux, this will return the equivalent of lsb_release -i.
- /// Android will return 'android'. Other systems may return
- /// nothing.
- ///
- /// @return
- /// A ConstString reference containing the OS distribution id.
- /// The return string will be all lower case, with whitespace
- /// replaced with underscores. The return string will be
- /// empty (result.AsCString() will return NULL) if the distribution
- /// cannot be obtained.
- //------------------------------------------------------------------
- static const ConstString &
- GetDistributionId ();
-
- //------------------------------------------------------------------
/// Get the process ID for the calling process.
///
/// @return
@@ -259,7 +145,7 @@ public:
///
/// This function call lets the current host OS do any thread
/// specific initialization that it needs, including naming the
- /// thread. No cleanup routine is exptected to be called
+ /// thread. No cleanup routine is expected to be called
///
/// @param[in] name
/// The current thread's name in the current process.
@@ -357,16 +243,6 @@ public:
SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name, size_t len);
//------------------------------------------------------------------
- /// Gets the FileSpec of the current process (the process that
- /// that is running the LLDB code).
- ///
- /// @return
- /// \b A file spec with the program name.
- //------------------------------------------------------------------
- static FileSpec
- GetProgramFileSpec ();
-
- //------------------------------------------------------------------
/// Given an address in the current process (the process that
/// is running the LLDB code), return the name of the module that
/// it comes from. This can be useful when you need to know the
@@ -383,8 +259,6 @@ public:
//------------------------------------------------------------------
static FileSpec
GetModuleFileSpecForHostAddress (const void *host_addr);
-
-
//------------------------------------------------------------------
/// If you have an executable that is in a bundle and want to get
@@ -410,7 +284,7 @@ public:
//------------------------------------------------------------------
/// When executable files may live within a directory, where the
/// directory represents an executable bundle (like the MacOSX
- /// app bundles), the locate the executable within the containing
+ /// app bundles), then locate the executable within the containing
/// bundle.
///
/// @param[in,out] file
@@ -426,28 +300,6 @@ public:
ResolveExecutableInBundle (FileSpec &file);
//------------------------------------------------------------------
- /// Find a resource files that are related to LLDB.
- ///
- /// Operating systems have different ways of storing shared
- /// libraries and related resources. This function abstracts the
- /// access to these paths.
- ///
- /// @param[in] path_type
- /// The type of LLDB resource path you are looking for. If the
- /// enumeration ends with "Dir", then only the \a file_spec's
- /// directory member gets filled in.
- ///
- /// @param[in] file_spec
- /// A file spec that gets filled in with the appriopriate path.
- ///
- /// @return
- /// \b true if \a resource_path was resolved, \a false otherwise.
- //------------------------------------------------------------------
- static bool
- GetLLDBPath (PathType path_type,
- FileSpec &file_spec);
-
- //------------------------------------------------------------------
/// Set a string that can be displayed if host application crashes.
///
/// Some operating systems have the ability to print a description
@@ -477,14 +329,19 @@ public:
static bool
GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info);
-#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__)
+#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined (__NetBSD__)
static short
GetPosixspawnFlags (ProcessLaunchInfo &launch_info);
static Error
LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid);
+
+ static bool AddPosixSpawnFileAction(void *file_actions, const FileAction *info, Log *log, Error &error);
#endif
+ static const lldb_private::UnixSignalsSP&
+ GetUnixSignals ();
+
static lldb::pid_t
LaunchApplication (const FileSpec &app_file_spec);
@@ -503,6 +360,9 @@ public:
static lldb::DataBufferSP
GetAuxvData (lldb_private::Process *process);
+ static lldb::DataBufferSP
+ GetAuxvData (lldb::pid_t pid);
+
static lldb::TargetSP
GetDummyTarget (Debugger &debugger);
@@ -515,79 +375,6 @@ public:
static size_t
GetEnvironment (StringList &env);
-
- enum DynamicLibraryOpenOptions
- {
- eDynamicLibraryOpenOptionLazy = (1u << 0), // Lazily resolve symbols in this dynamic library
- eDynamicLibraryOpenOptionLocal = (1u << 1), // Only open a shared library with local access (hide it from the global symbol namespace)
- eDynamicLibraryOpenOptionLimitGetSymbol = (1u << 2) // DynamicLibraryGetSymbol calls on this handle will only return matches from this shared library
- };
- static void *
- DynamicLibraryOpen (const FileSpec &file_spec,
- uint32_t options,
- Error &error);
-
- static Error
- DynamicLibraryClose (void *dynamic_library_handle);
-
- static void *
- DynamicLibraryGetSymbol (void *dynamic_library_handle,
- const char *symbol_name,
- Error &error);
-
- static Error
- MakeDirectory (const char* path, uint32_t mode);
-
- static Error
- GetFilePermissions (const char* path, uint32_t &file_permissions);
-
- static Error
- SetFilePermissions (const char* path, uint32_t file_permissions);
-
- static Error
- Symlink (const char *src, const char *dst);
-
- static Error
- Readlink (const char *path, char *buf, size_t buf_len);
-
- static Error
- Unlink (const char *path);
-
- static lldb::user_id_t
- OpenFile (const FileSpec& file_spec,
- uint32_t flags,
- uint32_t mode,
- Error &error);
-
- static bool
- CloseFile (lldb::user_id_t fd,
- Error &error);
-
- static uint64_t
- WriteFile (lldb::user_id_t fd,
- uint64_t offset,
- const void* src,
- uint64_t src_len,
- Error &error);
-
- static uint64_t
- ReadFile (lldb::user_id_t fd,
- uint64_t offset,
- void* dst,
- uint64_t dst_len,
- Error &error);
-
- static lldb::user_id_t
- GetFileSize (const FileSpec& file_spec);
-
- static bool
- GetFileExists (const FileSpec& file_spec);
-
- static bool
- CalculateMD5 (const FileSpec& file_spec,
- uint64_t &low,
- uint64_t &high);
-
};
} // namespace lldb_private
diff --git a/include/lldb/Host/HostGetOpt.h b/include/lldb/Host/HostGetOpt.h
index f4b2c87be230..761c1a118600 100644
--- a/include/lldb/Host/HostGetOpt.h
+++ b/include/lldb/Host/HostGetOpt.h
@@ -10,11 +10,15 @@
#ifndef _MSC_VER
+#ifdef _WIN32
+#define _BSD_SOURCE // Required so that getopt.h defines optreset
+#endif
+
#include <unistd.h>
#include <getopt.h>
#else
-#include <lldb/Host/windows/GetOptInc.h>
+#include <lldb/Host/windows/getopt/GetOptInc.h>
#endif
diff --git a/include/lldb/Host/HostInfo.h b/include/lldb/Host/HostInfo.h
new file mode 100644
index 000000000000..cbbf6cd2d49c
--- /dev/null
+++ b/include/lldb/Host/HostInfo.h
@@ -0,0 +1,61 @@
+//===-- HostInfoBase.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Host_HostInfo_h_
+#define lldb_Host_HostInfo_h_
+
+//----------------------------------------------------------------------
+/// @class HostInfo HostInfo.h "lldb/Host/HostInfo.h"
+/// @brief A class that provides host computer information.
+///
+/// HostInfo is a class that answers information about the host operating
+/// system. Note that HostInfo is NOT intended to be used to manipulate or
+/// control the operating system.
+///
+/// HostInfo is implemented in an OS-specific class (for example
+/// HostInfoWindows) in a separate file, and then typedefed to HostInfo here.
+/// Users of the class reference it as HostInfo::method().
+///
+/// Not all hosts provide the same functionality. It is important that methods
+/// only be implemented at the lowest level at which they make sense. It should
+/// be up to the clients of the class to ensure that they not attempt to call a
+/// method which doesn't make sense for a particular platform. For example,
+/// when implementing a method that only makes sense on a posix-compliant
+/// system, implement it on HostInfoPosix, and not on HostInfoBase with a
+/// default implementation. This way, users of HostInfo are required to think
+/// about the implications of calling a particular method and if used in a
+/// context where the method doesn't make sense, will generate a compiler error.
+///
+//----------------------------------------------------------------------
+
+#if defined(_WIN32)
+#include "lldb/Host/windows/HostInfoWindows.h"
+#define HOST_INFO_TYPE HostInfoWindows
+#elif defined(__linux__)
+#include "lldb/Host/linux/HostInfoLinux.h"
+#define HOST_INFO_TYPE HostInfoLinux
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include "lldb/Host/freebsd/HostInfoFreeBSD.h"
+#define HOST_INFO_TYPE HostInfoFreeBSD
+#elif defined(__APPLE__)
+#include "lldb/Host/macosx/HostInfoMacOSX.h"
+#define HOST_INFO_TYPE HostInfoMacOSX
+#else
+#include "lldb/Host/posix/HostInfoPosix.h"
+#define HOST_INFO_TYPE HostInfoPosix
+#endif
+
+namespace lldb_private
+{
+typedef HOST_INFO_TYPE HostInfo;
+}
+
+#undef HOST_INFO_TYPE
+
+#endif
diff --git a/include/lldb/Host/HostInfoBase.h b/include/lldb/Host/HostInfoBase.h
new file mode 100644
index 000000000000..f890dbc0b01b
--- /dev/null
+++ b/include/lldb/Host/HostInfoBase.h
@@ -0,0 +1,119 @@
+//===-- HostInfoBase.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Host_HostInfoBase_h_
+#define lldb_Host_HostInfoBase_h_
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "llvm/ADT/StringRef.h"
+
+#include <stdint.h>
+
+#include <string>
+
+namespace lldb_private
+{
+
+class FileSpec;
+
+class HostInfoBase
+{
+ private:
+ // Static class, unconstructable.
+ HostInfoBase() {}
+ ~HostInfoBase() {}
+
+ public:
+ static void Initialize();
+
+ //------------------------------------------------------------------
+ /// Returns the number of CPUs on this current host.
+ ///
+ /// @return
+ /// Number of CPUs on this current host, or zero if the number
+ /// of CPUs can't be determined on this host.
+ //------------------------------------------------------------------
+ static uint32_t GetNumberCPUS();
+
+ //------------------------------------------------------------------
+ /// Gets the host vendor string.
+ ///
+ /// @return
+ /// A const string object containing the host vendor name.
+ //------------------------------------------------------------------
+ static llvm::StringRef GetVendorString();
+
+ //------------------------------------------------------------------
+ /// Gets the host Operating System (OS) string.
+ ///
+ /// @return
+ /// A const string object containing the host OS name.
+ //------------------------------------------------------------------
+ static llvm::StringRef GetOSString();
+
+ //------------------------------------------------------------------
+ /// Gets the host target triple as a const string.
+ ///
+ /// @return
+ /// A const string object containing the host target triple.
+ //------------------------------------------------------------------
+ static llvm::StringRef GetTargetTriple();
+
+ //------------------------------------------------------------------
+ /// Gets the host architecture.
+ ///
+ /// @return
+ /// A const architecture object that represents the host
+ /// architecture.
+ //------------------------------------------------------------------
+ enum ArchitectureKind
+ {
+ eArchKindDefault, // The overall default architecture that applications will run on this host
+ eArchKind32, // If this host supports 32 bit programs, return the default 32 bit arch
+ eArchKind64 // If this host supports 64 bit programs, return the default 64 bit arch
+ };
+
+ static const ArchSpec &GetArchitecture(ArchitectureKind arch_kind = eArchKindDefault);
+
+ //------------------------------------------------------------------
+ /// Find a resource files that are related to LLDB.
+ ///
+ /// Operating systems have different ways of storing shared
+ /// libraries and related resources. This function abstracts the
+ /// access to these paths.
+ ///
+ /// @param[in] path_type
+ /// The type of LLDB resource path you are looking for. If the
+ /// enumeration ends with "Dir", then only the \a file_spec's
+ /// directory member gets filled in.
+ ///
+ /// @param[in] file_spec
+ /// A file spec that gets filled in with the appropriate path.
+ ///
+ /// @return
+ /// \b true if \a resource_path was resolved, \a false otherwise.
+ //------------------------------------------------------------------
+ static bool GetLLDBPath(lldb::PathType type, FileSpec &file_spec);
+
+ protected:
+ static bool ComputeSharedLibraryDirectory(FileSpec &file_spec);
+ static bool ComputeSupportExeDirectory(FileSpec &file_spec);
+ static bool ComputeTempFileDirectory(FileSpec &file_spec);
+ static bool ComputeHeaderDirectory(FileSpec &file_spec);
+ static bool ComputeSystemPluginsDirectory(FileSpec &file_spec);
+ static bool ComputeUserPluginsDirectory(FileSpec &file_spec);
+
+ static void ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64);
+};
+}
+
+#endif
diff --git a/include/lldb/Host/HostProcess.h b/include/lldb/Host/HostProcess.h
new file mode 100644
index 000000000000..2c10709ce942
--- /dev/null
+++ b/include/lldb/Host/HostProcess.h
@@ -0,0 +1,44 @@
+//===-- HostProcess.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Host_HostProcess_h_
+#define lldb_Host_HostProcess_h_
+
+//----------------------------------------------------------------------
+/// @class HostInfo HostInfo.h "lldb/Host/HostProcess.h"
+/// @brief A class that represents a running process on the host machine.
+///
+/// HostProcess allows querying and manipulation of processes running on the
+/// host machine. It is not intended to be represent a process which is
+/// being debugged, although the native debug engine of a platform may likely
+/// back inferior processes by a HostProcess.
+///
+/// HostProcess is implemented using static polymorphism so that on any given
+/// platform, an instance of HostProcess will always be able to bind statically
+/// to the concrete Process implementation for that platform. See HostInfo
+/// for more details.
+///
+//----------------------------------------------------------------------
+
+#if defined(_WIN32)
+#include "lldb/Host/windows/HostProcessWindows.h"
+#define HOST_PROCESS_TYPE HostProcessWindows
+#else
+#include "lldb/Host/posix/HostProcessPosix.h"
+#define HOST_PROCESS_TYPE HostProcessPosix
+#endif
+
+namespace lldb_private
+{
+ typedef HOST_PROCESS_TYPE HostProcess;
+}
+
+#undef HOST_PROCESS_TYPE
+
+#endif
diff --git a/include/lldb/Host/IOObject.h b/include/lldb/Host/IOObject.h
new file mode 100644
index 000000000000..532b1fd1bfce
--- /dev/null
+++ b/include/lldb/Host/IOObject.h
@@ -0,0 +1,61 @@
+//===-- IOObject.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_Host_Common_IOObject_h_
+#define liblldb_Host_Common_IOObject_h_
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class IOObject
+{
+public:
+ typedef enum
+ {
+ eFDTypeFile, // Other FD requiring read/write
+ eFDTypeSocket, // Socket requiring send/recv
+ } FDType;
+
+ // TODO: On Windows this should be a HANDLE, and wait should use
+ // WaitForMultipleObjects
+ typedef int WaitableHandle;
+ static const WaitableHandle kInvalidHandleValue;
+
+ IOObject(FDType type, bool should_close)
+ : m_fd_type(type)
+ , m_should_close_fd(should_close)
+ {
+ }
+ virtual ~IOObject() {}
+
+ virtual Error Read (void *buf, size_t &num_bytes) = 0;
+ virtual Error Write (const void *buf, size_t &num_bytes) = 0;
+ virtual bool IsValid() const = 0;
+ virtual Error Close() = 0;
+
+ FDType GetFdType() const { return m_fd_type; }
+
+ virtual WaitableHandle GetWaitableHandle() = 0;
+
+protected:
+ FDType m_fd_type;
+ bool m_should_close_fd; // True if this class should close the file descriptor when it goes away.
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (IOObject);
+};
+
+}
+
+#endif
diff --git a/include/lldb/Host/OptionParser.h b/include/lldb/Host/OptionParser.h
index ca83eeb1ed77..5aa7db5d34bf 100644
--- a/include/lldb/Host/OptionParser.h
+++ b/include/lldb/Host/OptionParser.h
@@ -16,18 +16,17 @@ struct option;
namespace lldb_private {
-typedef struct Option
+struct OptionDefinition;
+
+struct Option
{
- // name of long option
- const char *name;
- // one of no_argument, required_argument, and optional_argument:
- // whether option takes an argument
- int has_arg;
+ // The definition of the option that this refers to.
+ const OptionDefinition *definition;
// if not NULL, set *flag to val when option found
int *flag;
// if flag not NULL, value to set *flag to; else return value
int val;
-} Option;
+};
class OptionParser
{
diff --git a/include/lldb/Host/Pipe.h b/include/lldb/Host/Pipe.h
new file mode 100644
index 000000000000..b36c85cfbe87
--- /dev/null
+++ b/include/lldb/Host/Pipe.h
@@ -0,0 +1,83 @@
+//===-- Pipe.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_Pipe_h_
+#define liblldb_Pipe_h_
+#if defined(__cplusplus)
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Pipe Pipe.h "lldb/Host/Pipe.h"
+/// @brief A class that abtracts unix style pipes.
+///
+/// A class that abstracts the LLDB core from host pipe functionality.
+//----------------------------------------------------------------------
+class Pipe
+{
+public:
+ static int kInvalidDescriptor;
+
+ Pipe();
+
+ ~Pipe();
+
+ bool
+ Open();
+
+ bool
+ IsValid() const;
+
+ bool
+ ReadDescriptorIsValid() const;
+
+ bool
+ WriteDescriptorIsValid() const;
+
+ int
+ GetReadFileDescriptor() const;
+
+ int
+ GetWriteFileDescriptor() const;
+
+ // Close both descriptors
+ void
+ Close();
+
+ bool
+ CloseReadFileDescriptor();
+
+ bool
+ CloseWriteFileDescriptor();
+
+ int
+ ReleaseReadFileDescriptor();
+
+ int
+ ReleaseWriteFileDescriptor();
+
+ size_t
+ Read (void *buf, size_t size);
+
+ size_t
+ Write (const void *buf, size_t size);
+private:
+ int m_fds[2];
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_Pipe_h_
diff --git a/include/lldb/Host/Predicate.h b/include/lldb/Host/Predicate.h
index 6ddf20b67c69..f0e83ea5894b 100644
--- a/include/lldb/Host/Predicate.h
+++ b/include/lldb/Host/Predicate.h
@@ -78,7 +78,7 @@ public:
//------------------------------------------------------------------
/// Destructor.
///
- /// Destrory the condition, mutex, and T objects.
+ /// Destroy the condition, mutex, and T objects.
//------------------------------------------------------------------
~Predicate ()
{
@@ -112,7 +112,7 @@ public:
/// The new value to set.
///
/// @param[in] broadcast_type
- /// A value indicating when and if to broadast. See the
+ /// A value indicating when and if to broadcast. See the
/// PredicateBroadcastType enumeration for details.
///
/// @see Predicate::Broadcast()
@@ -140,7 +140,7 @@ public:
/// The bits to set in \a m_value.
///
/// @param[in] broadcast_type
- /// A value indicating when and if to broadast. See the
+ /// A value indicating when and if to broadcast. See the
/// PredicateBroadcastType enumeration for details.
///
/// @see Predicate::Broadcast()
@@ -168,7 +168,7 @@ public:
/// The bits to clear in \a m_value.
///
/// @param[in] broadcast_type
- /// A value indicating when and if to broadast. See the
+ /// A value indicating when and if to broadcast. See the
/// PredicateBroadcastType enumeration for details.
///
/// @see Predicate::Broadcast()
@@ -464,7 +464,7 @@ public:
protected:
//----------------------------------------------------------------------
- // pthread condition and mutex variable to controll access and allow
+ // pthread condition and mutex variable to control access and allow
// blocking between the main thread and the spotlight index thread.
//----------------------------------------------------------------------
T m_value; ///< The templatized value T that we are protecting access to
@@ -477,7 +477,7 @@ private:
/// Broadcast if needed.
///
/// Check to see if we need to broadcast to our condition variable
- /// depedning on the \a old_value and on the \a broadcast_type.
+ /// depending on the \a old_value and on the \a broadcast_type.
///
/// If \a broadcast_type is eBroadcastNever, no broadcast will be
/// sent.
diff --git a/include/lldb/Host/Socket.h b/include/lldb/Host/Socket.h
new file mode 100644
index 000000000000..0f3aa073001c
--- /dev/null
+++ b/include/lldb/Host/Socket.h
@@ -0,0 +1,103 @@
+//===-- Socket.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_Host_Socket_h_
+#define liblldb_Host_Socket_h_
+
+#include <string>
+
+#include "lldb/lldb-private.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Host/IOObject.h"
+#include "lldb/Host/Predicate.h"
+#include "lldb/Host/SocketAddress.h"
+
+#ifdef _WIN32
+#include "lldb/Host/windows/windows.h"
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+namespace llvm
+{
+ class StringRef;
+}
+
+namespace lldb_private {
+
+#if defined(_MSC_VER)
+ typedef SOCKET NativeSocket;
+#else
+ typedef int NativeSocket;
+#endif
+
+class Socket : public IOObject
+{
+public:
+ typedef enum
+ {
+ ProtocolTcp,
+ ProtocolUdp,
+ ProtocolUnixDomain
+ } SocketProtocol;
+
+ static const NativeSocket kInvalidSocketValue;
+
+ Socket(NativeSocket socket, SocketProtocol protocol, bool should_close);
+ ~Socket();
+
+ // Initialize a Tcp Socket object in listening mode. listen and accept are implemented
+ // separately because the caller may wish to manipulate or query the socket after it is
+ // initialized, but before entering a blocking accept.
+ static Error TcpListen(llvm::StringRef host_and_port, Socket *&socket, Predicate<uint16_t>* predicate);
+ static Error TcpConnect(llvm::StringRef host_and_port, Socket *&socket);
+ static Error UdpConnect(llvm::StringRef host_and_port, Socket *&send_socket, Socket *&recv_socket);
+ static Error UnixDomainConnect(llvm::StringRef host_and_port, Socket *&socket);
+ static Error UnixDomainAccept(llvm::StringRef host_and_port, Socket *&socket);
+
+ // Blocks on a listening socket until a connection is received. This method assumes that
+ // |this->m_socket| is a listening socket, created via either TcpListen() or via the native
+ // constructor that takes a NativeSocket, which itself was created via a call to |listen()|
+ Error BlockingAccept(llvm::StringRef host_and_port, Socket *&socket);
+
+ int GetOption (int level, int option_name, int &option_value);
+ int SetOption (int level, int option_name, int option_value);
+
+ static uint16_t GetPortNumber(const NativeSocket& socket);
+ uint16_t GetPortNumber () const;
+
+ NativeSocket GetNativeSocket () const { return m_socket; }
+ SocketProtocol GetSocketProtocol() const { return m_protocol; }
+
+ virtual Error Read (void *buf, size_t &num_bytes);
+ virtual Error Write (const void *buf, size_t &num_bytes);
+
+ virtual Error PreDisconnect();
+ virtual Error Close();
+
+ virtual bool IsValid() const { return m_socket != kInvalidSocketValue; }
+ virtual WaitableHandle GetWaitableHandle();
+
+protected:
+ static bool
+ DecodeHostAndPort (llvm::StringRef host_and_port,
+ std::string &host_str,
+ std::string &port_str,
+ int32_t& port,
+ Error *error_ptr);
+
+
+ SocketProtocol m_protocol;
+ NativeSocket m_socket;
+ SocketAddress m_udp_send_sockaddr; // Send address used for UDP connections.
+};
+}
+
+#endif
diff --git a/include/lldb/Host/SocketAddress.h b/include/lldb/Host/SocketAddress.h
index 4dc62102103a..3598a42a82d0 100644
--- a/include/lldb/Host/SocketAddress.h
+++ b/include/lldb/Host/SocketAddress.h
@@ -16,7 +16,7 @@
#ifdef _WIN32
#include "lldb/Host/windows/windows.h"
#include <winsock2.h>
-#include <WS2tcpip.h>
+#include <ws2tcpip.h>
typedef ADDRESS_FAMILY sa_family_t;
#else
#include <sys/socket.h>
@@ -82,7 +82,7 @@ public:
GetLength () const;
//------------------------------------------------------------------
- // Get the mex length for the the largest socket address supported.
+ // Get the max length for the largest socket address supported.
//------------------------------------------------------------------
static socklen_t
GetMaxLength ();
@@ -203,7 +203,7 @@ public:
// Conversion operators to allow getting the contents of this class
// as a pointer to the appropriate structure. This allows an instance
// of this class to be used in calls that take one of the sockaddr
- // structure variants without having to manally use the correct
+ // structure variants without having to manually use the correct
// accessor function.
//------------------------------------------------------------------
diff --git a/include/lldb/Host/Symbols.h b/include/lldb/Host/Symbols.h
index 652a614e6355..d6c86333d709 100644
--- a/include/lldb/Host/Symbols.h
+++ b/include/lldb/Host/Symbols.h
@@ -50,7 +50,7 @@ public:
// Locate the object and symbol file given a module specification.
//
// Locating the file can try to download the file from a corporate build
- // respository, or using any other means necessary to locate both the
+ // repository, or using any other means necessary to locate both the
// unstripped object file and the debug symbols.
// The force_lookup argument controls whether the external program is called
// unconditionally to find the symbol file, or if the user's settings are
diff --git a/include/lldb/Host/Terminal.h b/include/lldb/Host/Terminal.h
index 5ea88c515637..4a6017fc2eee 100644
--- a/include/lldb/Host/Terminal.h
+++ b/include/lldb/Host/Terminal.h
@@ -101,7 +101,7 @@ public:
///
/// @param[in] save_process_group
/// If \b true, save the process group settings, else do not
- /// save the process group setttings for a TTY.
+ /// save the process group settings for a TTY.
///
/// @return
/// Returns \b true if \a fd describes a TTY and if the state
diff --git a/include/lldb/Host/TimeValue.h b/include/lldb/Host/TimeValue.h
index ba230045307f..1792d343a6a6 100644
--- a/include/lldb/Host/TimeValue.h
+++ b/include/lldb/Host/TimeValue.h
@@ -15,11 +15,7 @@
#ifndef _MSC_VER
#include <sys/time.h>
-// BEGIN: MinGW work around
-#if !defined(_STRUCT_TIMESPEC) && !defined(HAVE_STRUCT_TIMESPEC)
-#include <pthread.h>
-#endif
-// END: MinGW work around
+
#endif
// C++ Includes
diff --git a/include/lldb/Host/freebsd/HostInfoFreeBSD.h b/include/lldb/Host/freebsd/HostInfoFreeBSD.h
new file mode 100644
index 000000000000..1404a4b1525c
--- /dev/null
+++ b/include/lldb/Host/freebsd/HostInfoFreeBSD.h
@@ -0,0 +1,29 @@
+//===-- HostInfoFreeBSD.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Host_freebsd_HostInfoFreeBSD_h_
+#define lldb_Host_freebsd_HostInfoFreeBSD_h_
+
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/posix/HostInfoPosix.h"
+
+namespace lldb_private
+{
+
+class HostInfoFreeBSD : public HostInfoPosix
+{
+ public:
+ static bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update);
+ static bool GetOSBuildString(std::string &s);
+ static bool GetOSKernelDescription(std::string &s);
+ static FileSpec GetProgramFileSpec();
+};
+}
+
+#endif
diff --git a/include/lldb/Host/posix/HostInfoPosix.h b/include/lldb/Host/posix/HostInfoPosix.h
new file mode 100644
index 000000000000..6e0dcbe48021
--- /dev/null
+++ b/include/lldb/Host/posix/HostInfoPosix.h
@@ -0,0 +1,40 @@
+//===-- HostInfoPosix.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Host_posix_HostInfoPosix_h_
+#define lldb_Host_posix_HostInfoPosix_h_
+
+#include "lldb/Host/HostInfoBase.h"
+
+namespace lldb_private
+{
+
+class HostInfoPosix : public HostInfoBase
+{
+ friend class HostInfoBase;
+
+ public:
+ static size_t GetPageSize();
+ static bool GetHostname(std::string &s);
+ static const char *LookupUserName(uint32_t uid, std::string &user_name);
+ static const char *LookupGroupName(uint32_t gid, std::string &group_name);
+
+ static uint32_t GetUserID();
+ static uint32_t GetGroupID();
+ static uint32_t GetEffectiveUserID();
+ static uint32_t GetEffectiveGroupID();
+
+ protected:
+ static bool ComputeSupportExeDirectory(FileSpec &file_spec);
+ static bool ComputeHeaderDirectory(FileSpec &file_spec);
+ static bool ComputePythonDirectory(FileSpec &file_spec);
+};
+}
+
+#endif
diff --git a/include/lldb/Host/posix/HostProcessPosix.h b/include/lldb/Host/posix/HostProcessPosix.h
new file mode 100644
index 000000000000..aa003ee4845e
--- /dev/null
+++ b/include/lldb/Host/posix/HostProcessPosix.h
@@ -0,0 +1,46 @@
+//===-- HostProcessPosix.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Host_HostProcesPosix_h_
+#define lldb_Host_HostProcesPosix_h_
+
+#include "lldb/lldb-types.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
+
+namespace lldb_private
+{
+
+class FileSpec;
+
+class HostProcessPosix
+{
+ public:
+ static const lldb::pid_t kInvalidProcessId;
+
+ HostProcessPosix();
+ ~HostProcessPosix();
+
+ Error Signal(int signo) const;
+ static Error Signal(lldb::pid_t pid, int signo);
+
+ Error Create(lldb::pid_t pid);
+ Error Terminate(int signo);
+ Error GetMainModule(FileSpec &file_spec) const;
+
+ lldb::pid_t GetProcessId() const;
+ bool IsRunning() const;
+
+ private:
+
+ lldb::pid_t m_pid;
+};
+}
+
+#endif
diff --git a/include/lldb/Interpreter/Args.h b/include/lldb/Interpreter/Args.h
index 27feca63e4ad..06617f1e5926 100644
--- a/include/lldb/Interpreter/Args.h
+++ b/include/lldb/Interpreter/Args.h
@@ -293,7 +293,7 @@ public:
/// A copy \a arg_cstr will be made.
///
/// @param[in] arg_cstr
- /// The argument to push on the front the the argument stack.
+ /// The argument to push on the front of the argument stack.
///
/// @param[in] quote_char
/// If the argument was originally quoted, put in the quote char here.
@@ -308,7 +308,7 @@ public:
/// Parse the arguments in the contained arguments.
///
/// The arguments that are consumed by the argument parsing process
- /// will be removed from the argument vector. The arguements that
+ /// will be removed from the argument vector. The arguments that
/// get processed start at the second argument. The first argument
/// is assumed to be the command and will not be touched.
///
@@ -430,7 +430,7 @@ public:
EncodeEscapeSequences (const char *src, std::string &dst);
// ExpandEscapeSequences will change a string of possibly non-printable
- // characters and expand them into text. So '\n' will turn into two chracters
+ // characters and expand them into text. So '\n' will turn into two characters
// like "\n" which is suitable for human reading. When a character is not
// printable and isn't one of the common in escape sequences listed in the
// help for EncodeEscapeSequences, then it will be encoded as octal. Printable
diff --git a/include/lldb/Interpreter/CommandCompletions.h b/include/lldb/Interpreter/CommandCompletions.h
index c4ab1b61adeb..9df3041584ea 100644
--- a/include/lldb/Interpreter/CommandCompletions.h
+++ b/include/lldb/Interpreter/CommandCompletions.h
@@ -195,7 +195,7 @@ public:
};
//----------------------------------------------------------------------
- // SouceFileCompleter implements the source file completer
+ // SourceFileCompleter implements the source file completer
//----------------------------------------------------------------------
class SourceFileCompleter : public Completer
{
diff --git a/include/lldb/Interpreter/CommandInterpreter.h b/include/lldb/Interpreter/CommandInterpreter.h
index bcb9b5538c84..c33d71a6dbbb 100644
--- a/include/lldb/Interpreter/CommandInterpreter.h
+++ b/include/lldb/Interpreter/CommandInterpreter.h
@@ -252,7 +252,7 @@ public:
// This version just returns matches, and doesn't compute the substring. It is here so the
// Help command can call it for the first argument.
- // word_complete tells whether a the completions are considered a "complete" response (so the
+ // word_complete tells whether the completions are considered a "complete" response (so the
// completer should complete the quote & put a space after the word.
int
@@ -332,6 +332,9 @@ public:
void
Initialize ();
+
+ void
+ Clear ();
void
SetScriptLanguage (lldb::ScriptLanguage lang);
@@ -476,12 +479,15 @@ protected:
std::string &line);
virtual ConstString
- GetControlSequence (char ch)
+ IOHandlerGetControlSequence (char ch)
{
if (ch == 'd')
return ConstString("quit\n");
return ConstString();
}
+
+ virtual bool
+ IOHandlerInterrupt (IOHandler &io_handler);
size_t
GetProcessOutput ();
diff --git a/include/lldb/Interpreter/CommandObject.h b/include/lldb/Interpreter/CommandObject.h
index 8544fd9f9c3f..7bdf55a393d7 100644
--- a/include/lldb/Interpreter/CommandObject.h
+++ b/include/lldb/Interpreter/CommandObject.h
@@ -269,7 +269,7 @@ public:
//
// Ensures a valid register context (from the selected frame if there
// is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx)
- // is availble from m_exe_ctx prior to executing the command. If a
+ // is available from m_exe_ctx prior to executing the command. If a
// target doesn't exist or is invalid, the command will fail and
// CommandObject::GetInvalidRegContextDescription() will be returned as
// the error. CommandObject subclasses can override the virtual function
@@ -460,25 +460,37 @@ public:
return NULL;
}
- CommandOverrideCallback
- GetOverrideCallback () const
+ bool
+ HasOverrideCallback () const
{
- return m_command_override_callback;
+ return m_command_override_callback || m_deprecated_command_override_callback;
}
- void *
- GetOverrideCallbackBaton () const
+ void
+ SetOverrideCallback (lldb::CommandOverrideCallback callback, void *baton)
{
- return m_command_override_baton;
+ m_deprecated_command_override_callback = callback;
+ m_command_override_baton = baton;
}
-
+
void
- SetOverrideCallback (CommandOverrideCallback callback, void *baton)
+ SetOverrideCallback (lldb::CommandOverrideCallbackWithResult callback, void *baton)
{
m_command_override_callback = callback;
m_command_override_baton = baton;
}
+ bool
+ InvokeOverrideCallback (const char **argv, CommandReturnObject &result)
+ {
+ if (m_command_override_callback)
+ return m_command_override_callback(m_command_override_baton, argv, result);
+ else if (m_deprecated_command_override_callback)
+ return m_deprecated_command_override_callback(m_command_override_baton, argv);
+ else
+ return false;
+ }
+
virtual bool
Execute (const char *args_string, CommandReturnObject &result) = 0;
@@ -540,7 +552,8 @@ protected:
bool m_is_alias;
Flags m_flags;
std::vector<CommandArgumentEntry> m_arguments;
- CommandOverrideCallback m_command_override_callback;
+ lldb::CommandOverrideCallback m_deprecated_command_override_callback;
+ lldb::CommandOverrideCallbackWithResult m_command_override_callback;
void * m_command_override_baton;
// Helper function to populate IDs or ID ranges as the command argument data
diff --git a/include/lldb/Interpreter/CommandOptionValidators.h b/include/lldb/Interpreter/CommandOptionValidators.h
new file mode 100644
index 000000000000..6be247ad4b65
--- /dev/null
+++ b/include/lldb/Interpreter/CommandOptionValidators.h
@@ -0,0 +1,30 @@
+//===-- CommandOptionValidators.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_CommandOptionValidators_h_
+#define liblldb_CommandOptionValidators_h_
+
+#include "lldb/lldb-private-types.h"
+
+namespace lldb_private {
+
+class Platform;
+class ExecutionContext;
+
+class PosixPlatformCommandOptionValidator : public OptionValidator
+{
+ virtual bool IsValid(Platform &platform, const ExecutionContext &target) const;
+ virtual const char* ShortConditionString() const;
+ virtual const char* LongConditionString() const;
+};
+
+} // namespace lldb_private
+
+
+#endif // liblldb_CommandOptionValidators_h_
diff --git a/include/lldb/Interpreter/CommandReturnObject.h b/include/lldb/Interpreter/CommandReturnObject.h
index acd03992e5e6..b922e1731d7e 100644
--- a/include/lldb/Interpreter/CommandReturnObject.h
+++ b/include/lldb/Interpreter/CommandReturnObject.h
@@ -160,9 +160,17 @@ public:
bool
HasResult ();
- bool GetDidChangeProcessState ();
+ bool
+ GetDidChangeProcessState ();
+
+ void
+ SetDidChangeProcessState (bool b);
- void SetDidChangeProcessState (bool b);
+ bool
+ GetInteractive () const;
+
+ void
+ SetInteractive (bool b);
private:
enum
@@ -176,6 +184,7 @@ private:
lldb::ReturnStatus m_status;
bool m_did_change_process_state;
+ bool m_interactive; // If true, then the input handle from the debugger will be hooked up
};
} // namespace lldb_private
diff --git a/include/lldb/Interpreter/Options.h b/include/lldb/Interpreter/Options.h
index 2b4ac1190557..6ecf08d28e75 100644
--- a/include/lldb/Interpreter/Options.h
+++ b/include/lldb/Interpreter/Options.h
@@ -159,7 +159,7 @@ public:
void
OutputFormattedUsageText (Stream &strm,
- const char *text,
+ const OptionDefinition &option_def,
uint32_t output_max_columns);
void
@@ -301,6 +301,12 @@ public:
int max_return_elements,
bool &word_complete,
StringList &matches);
+
+ CommandInterpreter&
+ GetInterpreter()
+ {
+ return m_interpreter;
+ }
protected:
// This is a set of options expressed as indexes into the options table for this Option.
diff --git a/include/lldb/Interpreter/PythonDataObjects.h b/include/lldb/Interpreter/PythonDataObjects.h
index 63f1ad5f67bf..a1145b6f33d9 100644
--- a/include/lldb/Interpreter/PythonDataObjects.h
+++ b/include/lldb/Interpreter/PythonDataObjects.h
@@ -62,9 +62,11 @@ namespace lldb_private {
{
if (py_obj != m_py_obj)
{
- Py_XDECREF(m_py_obj);
+ if (Py_IsInitialized())
+ Py_XDECREF(m_py_obj);
m_py_obj = py_obj;
- Py_XINCREF(m_py_obj);
+ if (Py_IsInitialized())
+ Py_XINCREF(m_py_obj);
}
return true;
}
diff --git a/include/lldb/Interpreter/ScriptInterpreter.h b/include/lldb/Interpreter/ScriptInterpreter.h
index 1d62c9b0fb52..5a8322f8eb4f 100644
--- a/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/include/lldb/Interpreter/ScriptInterpreter.h
@@ -254,16 +254,20 @@ public:
return error;
}
- virtual bool
+ virtual Error
ExportFunctionDefinitionToInterpreter (StringList &function_def)
{
- return false;
+ Error error;
+ error.SetErrorString("not implemented");
+ return error;
}
- virtual bool
+ virtual Error
GenerateBreakpointCommandCallbackData (StringList &input, std::string& output)
{
- return false;
+ Error error;
+ error.SetErrorString("not implemented");
+ return error;
}
virtual bool
@@ -359,24 +363,44 @@ public:
return lldb::ScriptInterpreterObjectSP();
}
- virtual bool
+ virtual Error
GenerateFunction(const char *signature, const StringList &input)
{
- return false;
+ Error error;
+ error.SetErrorString("unimplemented");
+ return error;
}
virtual void
- CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &options,
CommandReturnObject &result);
virtual void
CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
CommandReturnObject &result);
+ /// Set the specified text as the callback for the breakpoint.
+ Error
+ SetBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec,
+ const char *callback_text);
+
+ virtual Error
+ SetBreakpointCommandCallback (BreakpointOptions *bp_options,
+ const char *callback_text)
+ {
+ Error error;
+ error.SetErrorString("unimplemented");
+ return error;
+ }
+
+ void
+ SetBreakpointCommandCallbackFunction (std::vector<BreakpointOptions *> &bp_options_vec,
+ const char *function_name);
+
/// Set a one-liner as the callback for the breakpoint.
virtual void
- SetBreakpointCommandCallback (BreakpointOptions *bp_options,
- const char *oneliner)
+ SetBreakpointCommandCallbackFunction (BreakpointOptions *bp_options,
+ const char *function_name)
{
return;
}
@@ -398,6 +422,12 @@ public:
return false;
}
+ virtual void
+ Clear ()
+ {
+ // Clean up any ref counts to SBObjects that might be in global variables
+ }
+
virtual size_t
CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor)
{
@@ -545,9 +575,6 @@ public:
SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame,
SWIGPython_GetDynamicSetting swig_plugin_get);
- static void
- TerminateInterpreter ();
-
virtual void
ResetOutputFileHandle (FILE *new_fh) { } //By default, do nothing.
diff --git a/include/lldb/Interpreter/ScriptInterpreterPython.h b/include/lldb/Interpreter/ScriptInterpreterPython.h
index ba532808673f..14a62d67fde6 100644
--- a/include/lldb/Interpreter/ScriptInterpreterPython.h
+++ b/include/lldb/Interpreter/ScriptInterpreterPython.h
@@ -24,6 +24,8 @@
#include "lldb/Interpreter/PythonDataObjects.h"
#include "lldb/Host/Terminal.h"
+class IOHandlerPythonInterpreter;
+
namespace lldb_private {
class ScriptInterpreterPython :
@@ -56,7 +58,7 @@ public:
ExecuteMultipleLines (const char *in_string,
const ExecuteScriptOptions &options = ExecuteScriptOptions());
- bool
+ Error
ExportFunctionDefinitionToInterpreter (StringList &function_def);
bool
@@ -130,10 +132,10 @@ public:
lldb_private::CommandReturnObject& cmd_retobj,
Error& error);
- bool
+ Error
GenerateFunction(const char *signature, const StringList &input);
- bool
+ Error
GenerateBreakpointCommandCallbackData (StringList &input, std::string& output);
bool
@@ -170,6 +172,9 @@ public:
lldb::ScriptInterpreterObjectSP& callee_wrapper_sp,
std::string& retval);
+ virtual void
+ Clear ();
+
virtual bool
GetDocumentationForItem (const char* item, std::string& dest);
@@ -220,17 +225,21 @@ public:
AcquireInterpreterLock ();
void
- CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec,
CommandReturnObject &result);
void
CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
CommandReturnObject &result);
- /// Set a Python one-liner as the callback for the breakpoint.
- void
+ /// Set the callback body text into the callback for the breakpoint.
+ Error
SetBreakpointCommandCallback (BreakpointOptions *bp_options,
- const char *oneliner);
+ const char *callback_body);
+
+ void
+ SetBreakpointCommandCallbackFunction (BreakpointOptions *bp_options,
+ const char *function_name);
/// Set a one-liner as the callback for the watchpoint.
void
@@ -275,6 +284,19 @@ public:
}
+ PyThreadState *
+ GetThreadState()
+ {
+ return m_command_thread_state;
+ }
+
+ void
+ SetThreadState (PyThreadState *s)
+ {
+ if (s)
+ m_command_thread_state = s;
+ }
+
//----------------------------------------------------------------------
// IOHandlerDelegate
//----------------------------------------------------------------------
@@ -335,7 +357,8 @@ protected:
virtual
~ScriptInterpreterPythonObject()
{
- Py_XDECREF(m_object);
+ if (Py_IsInitialized())
+ Py_XDECREF(m_object);
m_object = NULL;
}
private:
@@ -392,7 +415,7 @@ public:
// FILE* m_tmp_fh;
PyGILState_STATE m_GILState;
};
-private:
+protected:
enum ActiveIOHandler {
eIOHandlerNone,
diff --git a/include/lldb/Symbol/Block.h b/include/lldb/Symbol/Block.h
index 4a305e3cbbec..59671b00b3b8 100644
--- a/include/lldb/Symbol/Block.h
+++ b/include/lldb/Symbol/Block.h
@@ -29,13 +29,13 @@ namespace lldb_private {
/// Block objects. The BlockList object contains a section offset
/// address range, and Block objects contain one or more ranges
/// which are offsets into that range. Blocks are can have discontiguous
-/// ranges within the BlockList adress range, and each block can
+/// ranges within the BlockList address range, and each block can
/// contain child blocks each with their own sets of ranges.
///
/// Each block has a variable list that represents local, argument, and
/// static variables that are scoped to the block.
///
-/// Inlined functions are representated by attaching a
+/// Inlined functions are represented by attaching a
/// InlineFunctionInfo shared pointer object to a block. Inlined
/// functions are represented as named blocks.
//----------------------------------------------------------------------
@@ -169,7 +169,7 @@ public:
/// Dump the block contents.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
///
/// @param[in] base_addr
/// The resolved start address of the Function's address
@@ -348,7 +348,7 @@ public:
/// Get const accessor for any inlined function information.
///
/// @return
- /// A comst pointer to any inlined function information, or NULL
+ /// A const pointer to any inlined function information, or NULL
/// if this is a regular block.
//------------------------------------------------------------------
const InlineFunctionInfo*
@@ -455,7 +455,7 @@ public:
GetRangeIndexContainingAddress (const Address& addr);
//------------------------------------------------------------------
- // Since blocks might have multiple discontiguous addresss ranges,
+ // Since blocks might have multiple discontiguous address ranges,
// we need to be able to get at any of the address ranges in a block.
//------------------------------------------------------------------
bool
@@ -477,7 +477,7 @@ protected:
collection m_children;
RangeList m_ranges;
lldb::InlineFunctionInfoSP m_inlineInfoSP; ///< Inlined function information.
- lldb::VariableListSP m_variable_list_sp; ///< The variable list for all local, static and paramter variables scoped to this block.
+ lldb::VariableListSP m_variable_list_sp; ///< The variable list for all local, static and parameter variables scoped to this block.
bool m_parsed_block_info:1, ///< Set to true if this block and it's children have all been parsed
m_parsed_block_variables:1,
m_parsed_child_blocks:1;
diff --git a/include/lldb/Symbol/ClangASTContext.h b/include/lldb/Symbol/ClangASTContext.h
index 75fc07b480e1..2bb911c6e566 100644
--- a/include/lldb/Symbol/ClangASTContext.h
+++ b/include/lldb/Symbol/ClangASTContext.h
@@ -18,7 +18,6 @@
#include <vector>
// Other libraries and framework includes
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "clang/AST/TemplateBase.h"
@@ -44,6 +43,9 @@ public:
ClangASTContext (const char *triple = NULL);
~ClangASTContext();
+
+ static ClangASTContext*
+ GetASTContext (clang::ASTContext* ast_ctx);
clang::ASTContext *
getASTContext();
@@ -72,8 +74,7 @@ public:
clang::DiagnosticConsumer *
getDiagnosticConsumer();
- clang::TargetOptions *
- getTargetOptions();
+ std::shared_ptr<clang::TargetOptions> &getTargetOptions();
clang::TargetInfo *
getTargetInfo();
@@ -94,7 +95,7 @@ public:
HasExternalSource ();
void
- SetExternalSource (llvm::OwningPtr<clang::ExternalASTSource> &ast_source_ap);
+ SetExternalSource (llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> &ast_source_ap);
void
RemoveExternalSource ();
@@ -259,8 +260,8 @@ public:
return 0;
}
- llvm::SmallVector<const char *, 8> names;
- llvm::SmallVector<clang::TemplateArgument, 8> args;
+ llvm::SmallVector<const char *, 2> names;
+ llvm::SmallVector<clang::TemplateArgument, 2> args;
};
clang::FunctionTemplateDecl *
@@ -395,6 +396,29 @@ public:
const ClangASTType &integer_qual_type);
//------------------------------------------------------------------
+ // Integer type functions
+ //------------------------------------------------------------------
+
+ ClangASTType
+ GetIntTypeFromBitSize (size_t bit_size, bool is_signed)
+ {
+ return GetIntTypeFromBitSize (getASTContext(), bit_size, is_signed);
+ }
+
+ static ClangASTType
+ GetIntTypeFromBitSize (clang::ASTContext *ast,
+ size_t bit_size, bool is_signed);
+
+ ClangASTType
+ GetPointerSizedIntType (bool is_signed)
+ {
+ return GetPointerSizedIntType (getASTContext(), is_signed);
+ }
+
+ static ClangASTType
+ GetPointerSizedIntType (clang::ASTContext *ast, bool is_signed);
+
+ //------------------------------------------------------------------
// Floating point functions
//------------------------------------------------------------------
@@ -419,7 +443,7 @@ protected:
std::unique_ptr<clang::SourceManager> m_source_manager_ap;
std::unique_ptr<clang::DiagnosticsEngine> m_diagnostics_engine_ap;
std::unique_ptr<clang::DiagnosticConsumer> m_diagnostic_consumer_ap;
- llvm::IntrusiveRefCntPtr<clang::TargetOptions> m_target_options_rp;
+ std::shared_ptr<clang::TargetOptions> m_target_options_rp;
std::unique_ptr<clang::TargetInfo> m_target_info_ap;
std::unique_ptr<clang::IdentifierTable> m_identifier_table_ap;
std::unique_ptr<clang::SelectorTable> m_selector_table_ap;
diff --git a/include/lldb/Symbol/ClangASTImporter.h b/include/lldb/Symbol/ClangASTImporter.h
index dc6ce6b5b95b..ee4fcada8a6d 100644
--- a/include/lldb/Symbol/ClangASTImporter.h
+++ b/include/lldb/Symbol/ClangASTImporter.h
@@ -166,7 +166,7 @@ public:
void BuildNamespaceMap (const clang::NamespaceDecl *decl);
//
- // Comleters for maps
+ // Completers for maps
//
class MapCompleter
diff --git a/include/lldb/Symbol/ClangASTType.h b/include/lldb/Symbol/ClangASTType.h
index 19b5d6ec6727..4dd17031e568 100644
--- a/include/lldb/Symbol/ClangASTType.h
+++ b/include/lldb/Symbol/ClangASTType.h
@@ -155,6 +155,9 @@ public:
bool
IsFunctionType (bool *is_variadic_ptr = NULL) const;
+ uint32_t
+ IsHomogeneousAggregate (ClangASTType* base_type_ptr) const;
+
size_t
GetNumberOfFunctionArguments () const;
@@ -210,7 +213,7 @@ public:
IsPointerOrReferenceType (ClangASTType *pointee_type = NULL) const;
bool
- IsReferenceType (ClangASTType *pointee_type = NULL) const;
+ IsReferenceType (ClangASTType *pointee_type = nullptr, bool* is_rvalue = nullptr) const;
bool
IsScalarType () const;
@@ -261,6 +264,9 @@ public:
ConstString
GetTypeName () const;
+ ConstString
+ GetDisplayTypeName () const;
+
uint32_t
GetTypeInfo (ClangASTType *pointee_or_element_clang_type = NULL) const;
@@ -309,7 +315,7 @@ public:
clang::DeclContext *decl_ctx) const;
ClangASTType
- GetArrayElementType (uint64_t& stride) const;
+ GetArrayElementType (uint64_t *stride = nullptr) const;
ClangASTType
GetCanonicalType () const;
@@ -317,7 +323,7 @@ public:
ClangASTType
GetFullyUnqualifiedType () const;
- // Returns -1 if this isn't a function of if the fucntion doesn't have a prototype
+ // Returns -1 if this isn't a function of if the function doesn't have a prototype
// Returns a value >= 0 if there is a prototype.
int
GetFunctionArgumentCount () const;
@@ -420,7 +426,6 @@ public:
ClangASTType
GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
- const char *parent_name,
size_t idx,
bool transparent_pointers,
bool omit_empty_base_classes,
@@ -431,7 +436,8 @@ public:
uint32_t &child_bitfield_bit_size,
uint32_t &child_bitfield_bit_offset,
bool &child_is_base_class,
- bool &child_is_deref_of_parent) const;
+ bool &child_is_deref_of_parent,
+ ValueObject *valobj) const;
// Lookup a child given a name. This function will match base class names
// and member member names in "clang_type" only, not descendants.
@@ -641,6 +647,9 @@ public:
AddressType address_type,
StreamString &new_value);
+ clang::EnumDecl *
+ GetAsEnumDecl () const;
+
clang::RecordDecl *
GetAsRecordDecl () const;
diff --git a/include/lldb/Symbol/ClangExternalASTSourceCommon.h b/include/lldb/Symbol/ClangExternalASTSourceCommon.h
index 72d77e74ca90..20c4b4354367 100644
--- a/include/lldb/Symbol/ClangExternalASTSourceCommon.h
+++ b/include/lldb/Symbol/ClangExternalASTSourceCommon.h
@@ -11,7 +11,7 @@
#define liblldb_ClangExternalASTSourceCommon_h
// Clang headers like to use NDEBUG inside of them to enable/disable debug
-// releated features using "#ifndef NDEBUG" preprocessor blocks to do one thing
+// related features using "#ifndef NDEBUG" preprocessor blocks to do one thing
// or another. This is bad because it means that if clang was built in release
// mode, it assumes that you are building in release mode which is not always
// the case. You can end up with functions that are defined as empty in header
diff --git a/include/lldb/Symbol/CompileUnit.h b/include/lldb/Symbol/CompileUnit.h
index 5de93670c5a7..f9238ebba18c 100644
--- a/include/lldb/Symbol/CompileUnit.h
+++ b/include/lldb/Symbol/CompileUnit.h
@@ -115,7 +115,7 @@ public:
/// parse the debug information.
///
/// @param[in] function_sp
- /// A shared pointer to the a Function object.
+ /// A shared pointer to the Function object.
//------------------------------------------------------------------
void
AddFunction(lldb::FunctionSP& function_sp);
@@ -178,7 +178,7 @@ public:
/// Dump the compile unit contents to the stream \a s.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
///
/// @param[in] show_context
/// If \b true, variables will dump their symbol context
@@ -199,7 +199,7 @@ public:
///
/// Multiple calls to this function can find all entries that match
/// a given file and line by starting with \a start_idx equal to zero,
- /// and calling this function back with the return valeu + 1.
+ /// and calling this function back with the return value + 1.
///
/// @param[in] start_idx
/// The zero based index at which to start looking for matches.
@@ -377,7 +377,7 @@ public:
/// using a LineEntry base address will be able to be resolved.
///
/// @param[out] sc_list
- /// A SymbolContext list class that willl get any matching
+ /// A SymbolContext list class that will get any matching
/// entries appended to.
///
/// @return
diff --git a/include/lldb/Symbol/DWARFCallFrameInfo.h b/include/lldb/Symbol/DWARFCallFrameInfo.h
index 13a14f8c4041..e67a5a2a8e2c 100644
--- a/include/lldb/Symbol/DWARFCallFrameInfo.h
+++ b/include/lldb/Symbol/DWARFCallFrameInfo.h
@@ -100,7 +100,7 @@ private:
typedef std::shared_ptr<CIE> CIESP;
- typedef std::map<off_t, CIESP> cie_map_t;
+ typedef std::map<dw_offset_t, CIESP> cie_map_t;
// Start address (file address), size, offset of FDE location
// used for finding an FDE for a given File address; the start address field is
diff --git a/include/lldb/Symbol/Declaration.h b/include/lldb/Symbol/Declaration.h
index f014571595f0..73dede556eae 100644
--- a/include/lldb/Symbol/Declaration.h
+++ b/include/lldb/Symbol/Declaration.h
@@ -136,7 +136,7 @@ public:
/// supplied stream \a s.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
//------------------------------------------------------------------
void
Dump (Stream *s, bool show_fullpaths) const;
@@ -236,7 +236,7 @@ public:
/// Set accessor for the declaration file specification.
///
/// @param[in] file_spec
- /// The new declaration file specifciation.
+ /// The new declaration file specification.
//------------------------------------------------------------------
void
SetFile (const FileSpec& file_spec)
diff --git a/include/lldb/Symbol/FuncUnwinders.h b/include/lldb/Symbol/FuncUnwinders.h
index 7af063402289..0cf584239f95 100644
--- a/include/lldb/Symbol/FuncUnwinders.h
+++ b/include/lldb/Symbol/FuncUnwinders.h
@@ -21,7 +21,7 @@ public:
// This is often sourced from the eh_frame exception handling info
// 2. Unwinding from a non-call site (any location in the function)
// This is often done by analyzing the function prologue assembly
- // langauge instructions
+ // language instructions
// 3. A fast unwind method for this function which only retrieves a
// limited set of registers necessary to walk the stack
// 4. An architectural default unwind plan when none of the above are
@@ -31,7 +31,7 @@ public:
// instructions are finished for migrating breakpoints past the
// stack frame setup instructions when we don't have line table information.
- FuncUnwinders (lldb_private::UnwindTable& unwind_table, const lldb::UnwindAssemblySP& assembly_profiler, AddressRange range);
+ FuncUnwinders (lldb_private::UnwindTable& unwind_table, AddressRange range);
~FuncUnwinders ();
@@ -44,7 +44,7 @@ public:
GetUnwindPlanAtCallSite (int current_offset);
lldb::UnwindPlanSP
- GetUnwindPlanAtNonCallSite (lldb_private::Thread& thread);
+ GetUnwindPlanAtNonCallSite (Target& target, lldb_private::Thread& thread, int current_offset);
lldb::UnwindPlanSP
GetUnwindPlanFastUnwind (lldb_private::Thread& Thread);
@@ -76,8 +76,11 @@ public:
InvalidateNonCallSiteUnwindPlan (lldb_private::Thread& Thread);
private:
+
+ lldb::UnwindAssemblySP
+ GetUnwindAssemblyProfiler ();
+
UnwindTable& m_unwind_table;
- lldb::UnwindAssemblySP m_assembly_profiler;
AddressRange m_range;
Mutex m_mutex;
diff --git a/include/lldb/Symbol/Function.h b/include/lldb/Symbol/Function.h
index dcea24c0b632..5954cf520d70 100644
--- a/include/lldb/Symbol/Function.h
+++ b/include/lldb/Symbol/Function.h
@@ -24,7 +24,7 @@ namespace lldb_private {
/// @class FunctionInfo Function.h "lldb/Symbol/Function.h"
/// @brief A class that contains generic function information.
///
-/// This provides generic function information that gets resused between
+/// This provides generic function information that gets reused between
/// inline functions and function types.
//----------------------------------------------------------------------
class FunctionInfo
@@ -94,7 +94,7 @@ public:
/// supplied stream \a s.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
//------------------------------------------------------------------
void
Dump (Stream *s, bool show_fullpaths) const;
@@ -234,7 +234,7 @@ public:
/// supplied stream \a s.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
//------------------------------------------------------------------
void
Dump(Stream *s, bool show_fullpaths) const;
@@ -316,14 +316,14 @@ private:
/// (Function::m_type), and contains lexical blocks
/// (Function::m_blocks).
///
-/// The function inforation is split into a few pieces:
+/// The function information is split into a few pieces:
/// @li The concrete instance information
/// @li The abstract information
///
/// The abstract information is found in the function type (Type) that
/// describes a function information, return type and parameter types.
///
-/// The concreate information is the address range information and
+/// The concrete information is the address range information and
/// specific locations for an instance of this function.
//----------------------------------------------------------------------
class Function :
@@ -547,7 +547,7 @@ public:
//------------------------------------------------------------------
/// Get accessor for the type that describes the function
- /// return value type, and paramter types.
+ /// return value type, and parameter types.
///
/// @return
/// A type object pointer.
@@ -557,7 +557,7 @@ public:
//------------------------------------------------------------------
/// Get const accessor for the type that describes the function
- /// return value type, and paramter types.
+ /// return value type, and parameter types.
///
/// @return
/// A const type object pointer.
@@ -578,7 +578,7 @@ public:
/// supplied stream \a s.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
///
/// @param[in] show_context
/// If \b true, variables will dump their symbol context
diff --git a/include/lldb/Symbol/LineEntry.h b/include/lldb/Symbol/LineEntry.h
index d7750cd34916..082caea3b12f 100644
--- a/include/lldb/Symbol/LineEntry.h
+++ b/include/lldb/Symbol/LineEntry.h
@@ -59,7 +59,7 @@ struct LineEntry
/// supplied stream \a s.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
///
/// @param[in] comp_unit
/// The compile unit object that contains the support file
@@ -98,7 +98,7 @@ struct LineEntry
/// line entry to the supplied stream \a s.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
///
/// @param[in] comp_unit
/// The compile unit object that contains the support file
diff --git a/include/lldb/Symbol/LineTable.h b/include/lldb/Symbol/LineTable.h
index 477c8455ded8..3e25ad17e94e 100644
--- a/include/lldb/Symbol/LineTable.h
+++ b/include/lldb/Symbol/LineTable.h
@@ -85,7 +85,7 @@ public:
bool is_epilogue_begin,
bool is_terminal_entry);
- // Used to instantiate the LineSequence helper classw
+ // Used to instantiate the LineSequence helper class
LineSequence*
CreateLineSequenceContainer ();
@@ -111,7 +111,7 @@ public:
/// Dump all line entries in this line table to the stream \a s.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
///
/// @param[in] style
/// The display style for the address.
diff --git a/include/lldb/Symbol/ObjectContainer.h b/include/lldb/Symbol/ObjectContainer.h
index 7fb686245057..679e8f03b67a 100644
--- a/include/lldb/Symbol/ObjectContainer.h
+++ b/include/lldb/Symbol/ObjectContainer.h
@@ -85,7 +85,7 @@ public:
/// if it has been parsed.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
//------------------------------------------------------------------
virtual void
Dump (Stream *s) const = 0;
@@ -168,7 +168,7 @@ public:
/// and the next plug-in can attempt to parse an object file.
///
/// @return
- /// Returns \b true if the header was parsed succesfully, \b
+ /// Returns \b true if the header was parsed successfully, \b
/// false otherwise.
//------------------------------------------------------------------
virtual bool
diff --git a/include/lldb/Symbol/ObjectFile.h b/include/lldb/Symbol/ObjectFile.h
index afa1f9b40902..bdc6ae8c9e81 100644
--- a/include/lldb/Symbol/ObjectFile.h
+++ b/include/lldb/Symbol/ObjectFile.h
@@ -21,6 +21,36 @@
#include "lldb/Symbol/UnwindTable.h"
namespace lldb_private {
+
+class ObjectFileJITDelegate
+{
+public:
+ ObjectFileJITDelegate ()
+ {
+ }
+
+ virtual
+ ~ObjectFileJITDelegate()
+ {
+ }
+
+ virtual lldb::ByteOrder
+ GetByteOrder () const = 0;
+
+ virtual uint32_t
+ GetAddressByteSize () const = 0;
+
+ virtual void
+ PopulateSymtab (lldb_private::ObjectFile *obj_file,
+ lldb_private::Symtab &symtab) = 0;
+
+ virtual void
+ PopulateSectionList (lldb_private::ObjectFile *obj_file,
+ lldb_private::SectionList &section_list) = 0;
+
+ virtual bool
+ GetArchitecture (lldb_private::ArchSpec &arch) = 0;
+};
//----------------------------------------------------------------------
/// @class ObjectFile ObjectFile.h "lldb/Symbol/ObjectFile.h"
@@ -32,23 +62,11 @@ namespace lldb_private {
/// for an object file.
///
/// Object files can be represented by the entire file, or by part of a
-/// file. Examples of object files that are part of a file include
-/// object files that contain information for multiple architectures in
-/// the same file, or archive files that contain multiple objects
-/// (ranlib archives) (possibly for multiple architectures as well).
+/// file. An example of a partial file ObjectFile is one that contains
+/// information for one of multiple architectures in the same file.
///
-/// Object archive files (e.g. ranlib archives) can contain
-/// multiple .o (object) files that must be selected by index or by name.
-/// The number of objects that an ObjectFile contains can be determined
-/// using the ObjectFile::GetNumObjects() const
-/// function, and followed by a call to
-/// ObjectFile::SelectObjectAtIndex (uint32_t) to change the currently
-/// selected object. Objects can also be selected by name using the
-/// ObjectFile::SelectObject(const char *) function.
-///
-/// Once an architecture is selected (and an object is selected for
-/// for archives), the object file information can be extracted from
-/// this abstract class.
+/// Once an architecture is selected the object file information can be
+/// extracted from this abstract class.
//----------------------------------------------------------------------
class ObjectFile:
public std::enable_shared_from_this<ObjectFile>,
@@ -68,6 +86,7 @@ public:
eTypeObjectFile, /// An intermediate object file
eTypeSharedLibrary, /// A shared library that can be used during execution
eTypeStubLibrary, /// A library that can be linked against but not used for execution
+ eTypeJIT, /// JIT code that has symbols, sections and possibly debug info
eTypeUnknown
} Type;
@@ -77,7 +96,8 @@ public:
eStrataUnknown,
eStrataUser,
eStrataKernel,
- eStrataRawImage
+ eStrataRawImage,
+ eStrataJIT
} Strata;
//------------------------------------------------------------------
@@ -91,7 +111,7 @@ public:
const FileSpec *file_spec_ptr,
lldb::offset_t file_offset,
lldb::offset_t length,
- lldb::DataBufferSP& data_sp,
+ const lldb::DataBufferSP& data_sp,
lldb::offset_t data_offset);
ObjectFile (const lldb::ModuleSP &module_sp,
@@ -117,7 +137,7 @@ public:
/// if it has been parsed.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
//------------------------------------------------------------------
virtual void
Dump (Stream *s) = 0;
@@ -354,6 +374,16 @@ public:
virtual void
CreateSections (SectionList &unified_section_list) = 0;
+
+ //------------------------------------------------------------------
+ /// Notify the ObjectFile that the file addresses in the Sections
+ /// for this module have been changed.
+ //------------------------------------------------------------------
+ virtual void
+ SectionFileAddressesChanged ()
+ {
+ }
+
//------------------------------------------------------------------
/// Gets the symbol table for the currently selected architecture
/// (and object for archives).
@@ -439,7 +469,7 @@ public:
/// Gets the symbol file spec list for this object file.
///
/// If the object file format contains a debug symbol file link,
- /// the values will be return in the FileSpecList.
+ /// the values will be returned in the FileSpecList.
///
/// @return
/// Returns filespeclist.
@@ -451,6 +481,21 @@ public:
}
//------------------------------------------------------------------
+ /// Gets the file spec list of libraries re-exported by this object file.
+ ///
+ /// If the object file format has the notion of one library re-exporting the symbols from another,
+ /// the re-exported libraries will be returned in the FileSpecList.
+ ///
+ /// @return
+ /// Returns filespeclist.
+ //------------------------------------------------------------------
+ virtual lldb_private::FileSpecList
+ GetReExportedLibraries ()
+ {
+ return FileSpecList();
+ }
+
+ //------------------------------------------------------------------
/// Sets the load address for an entire module, assuming a rigid
/// slide of sections, if possible in the implementation.
///
@@ -486,7 +531,7 @@ public:
/// and the next plug-in can attempt to parse an object file.
///
/// @return
- /// Returns \b true if the header was parsed succesfully, \b
+ /// Returns \b true if the header was parsed successfully, \b
/// false otherwise.
//------------------------------------------------------------------
virtual bool
@@ -751,17 +796,17 @@ public:
size_t byte_size);
size_t
- GetData (off_t offset, size_t length, DataExtractor &data) const;
+ GetData (lldb::offset_t offset, size_t length, DataExtractor &data) const;
size_t
- CopyData (off_t offset, size_t length, void *dst) const;
+ CopyData (lldb::offset_t offset, size_t length, void *dst) const;
- size_t
+ virtual size_t
ReadSectionData (const Section *section,
- off_t section_offset,
+ lldb::offset_t section_offset,
void *dst,
size_t dst_len) const;
- size_t
+ virtual size_t
ReadSectionData (const Section *section,
DataExtractor& section_data) const;
diff --git a/include/lldb/Symbol/Symbol.h b/include/lldb/Symbol/Symbol.h
index db32ba373e42..0dd04b7112bc 100644
--- a/include/lldb/Symbol/Symbol.h
+++ b/include/lldb/Symbol/Symbol.h
@@ -92,6 +92,9 @@ public:
return m_addr_range.GetBaseAddress();
}
+ lldb::addr_t
+ ResolveCallableAddress(Target &target) const;
+
const ConstString &
GetName () const
{
@@ -135,7 +138,7 @@ public:
SetReExportedSymbolSharedLibrary (const FileSpec &fspec);
Symbol *
- ResolveReExportedSymbol (Target &target);
+ ResolveReExportedSymbol (Target &target) const;
uint32_t
GetSiblingIndex () const;
@@ -303,7 +306,15 @@ public:
Stream &strm);
protected:
-
+ // This is the internal guts of ResolveReExportedSymbol, it assumes reexport_name is not null, and that module_spec
+ // is valid. We track the modules we've already seen to make sure we don't get caught in a cycle.
+
+ Symbol *
+ ResolveReExportedSymbolInModuleSpec (Target &target,
+ ConstString &reexport_name,
+ lldb_private::ModuleSpec &module_spec,
+ lldb_private::ModuleList &seen_modules) const;
+
uint32_t m_uid; // User ID (usually the original symbol table index)
uint16_t m_type_data; // data specific to m_type
uint16_t m_type_data_resolved:1, // True if the data in m_type_data has already been calculated
diff --git a/include/lldb/Symbol/SymbolContext.h b/include/lldb/Symbol/SymbolContext.h
index 6fdd828bd9f2..c26b7a0b9a10 100644
--- a/include/lldb/Symbol/SymbolContext.h
+++ b/include/lldb/Symbol/SymbolContext.h
@@ -140,7 +140,7 @@ public:
/// supplied stream \a s.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
//------------------------------------------------------------------
void
Dump (Stream *s, Target *target) const;
@@ -157,7 +157,7 @@ public:
/// was stopped will be displayed.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
///
/// @param[in] so_addr
/// The resolved section offset address.
@@ -409,7 +409,7 @@ private:
/// the result of a query that can contain a multiple results. Examples
/// of such queries include:
/// @li Looking up a function by name.
-/// @li Finding all addressses for a specified file and line number.
+/// @li Finding all addresses for a specified file and line number.
//----------------------------------------------------------------------
class SymbolContextList
{
@@ -465,7 +465,7 @@ public:
/// the list to the supplied stream \a s.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
//------------------------------------------------------------------
void
Dump(Stream *s, Target *target) const;
diff --git a/include/lldb/Symbol/SymbolContextScope.h b/include/lldb/Symbol/SymbolContextScope.h
index 693cc0131e27..a02b4523a4c0 100644
--- a/include/lldb/Symbol/SymbolContextScope.h
+++ b/include/lldb/Symbol/SymbolContextScope.h
@@ -75,7 +75,7 @@ public:
~SymbolContextScope () {}
//------------------------------------------------------------------
- /// Reconstruct the object's symbolc context into \a sc.
+ /// Reconstruct the object's symbol context into \a sc.
///
/// The object should fill in as much of the SymbolContext as it
/// can so function calls that require a symbol context can be made
@@ -119,11 +119,11 @@ public:
}
//------------------------------------------------------------------
- /// Dump the object's symbolc context to the stream \a s.
+ /// Dump the object's symbol context to the stream \a s.
///
/// The object should dump its symbol context to the stream \a s.
/// This function is widely used in the DumpDebug and verbose output
- /// for lldb objets.
+ /// for lldb objects.
///
/// @param[in] s
/// The stream to which to dump the object's symbol context.
diff --git a/include/lldb/Symbol/SymbolFile.h b/include/lldb/Symbol/SymbolFile.h
index 5b774e3a7d13..6df3d49fc464 100644
--- a/include/lldb/Symbol/SymbolFile.h
+++ b/include/lldb/Symbol/SymbolFile.h
@@ -67,7 +67,7 @@ public:
/// Each symbol file gets to respond with a mask of abilities that
/// it supports for each object file. This happens when we are
/// trying to figure out which symbol file plug-in will get used
- /// for a given object file. The plug-in that resoonds with the
+ /// for a given object file. The plug-in that responds with the
/// best mix of "SymbolFile::Abilities" bits set, will get chosen to
/// be the symbol file parser. This allows each plug-in to check for
/// sections that contain data a symbol file plug-in would need. For
@@ -152,6 +152,16 @@ public:
ObjectFile* GetObjectFile() { return m_obj_file; }
const ObjectFile* GetObjectFile() const { return m_obj_file; }
+
+ //------------------------------------------------------------------
+ /// Notify the SymbolFile that the file addresses in the Sections
+ /// for this module have been changed.
+ //------------------------------------------------------------------
+ virtual void
+ SectionFileAddressesChanged ()
+ {
+ }
+
protected:
ObjectFile* m_obj_file; // The object file that symbols can be extracted from.
diff --git a/include/lldb/Symbol/SymbolVendor.h b/include/lldb/Symbol/SymbolVendor.h
index 0eeea4eb466b..82f902d4e07b 100644
--- a/include/lldb/Symbol/SymbolVendor.h
+++ b/include/lldb/Symbol/SymbolVendor.h
@@ -173,6 +173,13 @@ public:
ClearSymtab ();
//------------------------------------------------------------------
+ /// Notify the SymbolVendor that the file addresses in the Sections
+ /// for this module have been changed.
+ //------------------------------------------------------------------
+ virtual void
+ SectionFileAddressesChanged ();
+
+ //------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
virtual ConstString
diff --git a/include/lldb/Symbol/Symtab.h b/include/lldb/Symbol/Symtab.h
index 5dfb1c822d51..dc08333e22fb 100644
--- a/include/lldb/Symbol/Symtab.h
+++ b/include/lldb/Symbol/Symtab.h
@@ -46,6 +46,7 @@ public:
Symbol * Resize (size_t count);
uint32_t AddSymbol(const Symbol& symbol);
size_t GetNumSymbols() const;
+ void SectionFileAddressesChanged ();
void Dump(Stream *s, Target *target, SortOrder sort_type);
void Dump(Stream *s, Target *target, std::vector<uint32_t>& indexes) const;
uint32_t GetIndexForSymbol (const Symbol *symbol) const;
diff --git a/include/lldb/Symbol/Type.h b/include/lldb/Symbol/Type.h
index da327439936c..eaa150e78ace 100644
--- a/include/lldb/Symbol/Type.h
+++ b/include/lldb/Symbol/Type.h
@@ -17,6 +17,8 @@
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Symbol/Declaration.h"
+#include "llvm/ADT/APSInt.h"
+
#include <set>
namespace lldb_private {
@@ -103,6 +105,11 @@ public:
void
DumpTypeName(Stream *s);
+ // Since Type instances only keep a "SymbolFile *" internally, other classes
+ // like TypeImpl need make sure the module is still around before playing with
+ // Type instances. They can store a weak pointer to the Module;
+ lldb::ModuleSP
+ GetModule();
void
GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_name);
@@ -306,16 +313,18 @@ protected:
// these classes are used to back the SBType* objects
-class TypePair {
-private:
- ClangASTType clang_type;
- lldb::TypeSP type_sp;
-
+class TypePair
+{
public:
- TypePair () : clang_type(), type_sp() {}
+ TypePair () :
+ clang_type(),
+ type_sp()
+ {
+ }
+
TypePair (ClangASTType type) :
- clang_type(type),
- type_sp()
+ clang_type(type),
+ type_sp()
{
}
@@ -368,6 +377,16 @@ public:
return ConstString ();
}
+ ConstString
+ GetDisplayTypeName () const
+ {
+ if (type_sp)
+ return type_sp->GetClangForwardType().GetDisplayTypeName();
+ if (clang_type)
+ return clang_type.GetDisplayTypeName();
+ return ConstString();
+ }
+
void
SetType (ClangASTType type)
{
@@ -455,6 +474,17 @@ public:
{
return clang_type.GetASTContext();
}
+
+ lldb::ModuleSP
+ GetModule () const
+ {
+ if (type_sp)
+ return type_sp->GetModule();
+ return lldb::ModuleSP();
+ }
+protected:
+ ClangASTType clang_type;
+ lldb::TypeSP type_sp;
};
class TypeImpl
@@ -467,30 +497,30 @@ public:
TypeImpl(const TypeImpl& rhs);
- TypeImpl (lldb::TypeSP type_sp);
+ TypeImpl (const lldb::TypeSP &type_sp);
- TypeImpl (ClangASTType clang_type);
+ TypeImpl (const ClangASTType &clang_type);
- TypeImpl (lldb::TypeSP type_sp, ClangASTType dynamic);
+ TypeImpl (const lldb::TypeSP &type_sp, const ClangASTType &dynamic);
- TypeImpl (ClangASTType clang_type, ClangASTType dynamic);
+ TypeImpl (const ClangASTType &clang_type, const ClangASTType &dynamic);
- TypeImpl (TypePair pair, ClangASTType dynamic);
+ TypeImpl (const TypePair &pair, const ClangASTType &dynamic);
void
- SetType (lldb::TypeSP type_sp);
+ SetType (const lldb::TypeSP &type_sp);
void
- SetType (ClangASTType clang_type);
+ SetType (const ClangASTType &clang_type);
void
- SetType (lldb::TypeSP type_sp, ClangASTType dynamic);
+ SetType (const lldb::TypeSP &type_sp, const ClangASTType &dynamic);
void
- SetType (ClangASTType clang_type, ClangASTType dynamic);
+ SetType (const ClangASTType &clang_type, const ClangASTType &dynamic);
void
- SetType (TypePair pair, ClangASTType dynamic);
+ SetType (const TypePair &pair, const ClangASTType &dynamic);
TypeImpl&
operator = (const TypeImpl& rhs);
@@ -511,6 +541,9 @@ public:
ConstString
GetName () const;
+ ConstString
+ GetDisplayTypeName () const;
+
TypeImpl
GetPointerType () const;
@@ -543,6 +576,11 @@ public:
lldb::DescriptionLevel description_level);
private:
+
+ bool
+ CheckModule (lldb::ModuleSP &module_sp) const;
+
+ lldb::ModuleWP m_module_wp;
TypePair m_static_type;
ClangASTType m_dynamic_type;
};
@@ -772,7 +810,105 @@ private:
TypePair m_type_pair;
ConstString m_type_name;
};
-
+
+class TypeEnumMemberImpl
+{
+public:
+ TypeEnumMemberImpl () :
+ m_integer_type_sp(),
+ m_name("<invalid>"),
+ m_value(),
+ m_valid(false)
+ {
+ }
+
+ TypeEnumMemberImpl (const clang::EnumConstantDecl* enum_member_decl,
+ const lldb_private::ClangASTType& integer_type);
+
+ TypeEnumMemberImpl (const TypeEnumMemberImpl& rhs) :
+ m_integer_type_sp(rhs.m_integer_type_sp),
+ m_name(rhs.m_name),
+ m_value(rhs.m_value),
+ m_valid(rhs.m_valid)
+ {
+ }
+
+ TypeEnumMemberImpl&
+ operator = (const TypeEnumMemberImpl& rhs);
+
+ bool
+ IsValid ()
+ {
+ return m_valid;
+ }
+
+ const ConstString &
+ GetName () const
+ {
+ return m_name;
+ }
+
+ const lldb::TypeImplSP &
+ GetIntegerType () const
+ {
+ return m_integer_type_sp;
+ }
+
+ uint64_t
+ GetValueAsUnsigned () const
+ {
+ return *m_value.getRawData();
+ }
+
+ int64_t
+ GetValueAsSigned () const
+ {
+ return (int64_t) *m_value.getRawData();
+ }
+
+protected:
+ lldb::TypeImplSP m_integer_type_sp;
+ ConstString m_name;
+ llvm::APSInt m_value;
+ bool m_valid;
+};
+
+class TypeEnumMemberListImpl
+{
+public:
+ TypeEnumMemberListImpl() :
+ m_content()
+ {
+ }
+
+ void
+ Append (const lldb::TypeEnumMemberImplSP& type)
+ {
+ m_content.push_back(type);
+ }
+
+ void
+ Append (const lldb_private::TypeEnumMemberListImpl& type_list);
+
+ lldb::TypeEnumMemberImplSP
+ GetTypeEnumMemberAtIndex(size_t idx)
+ {
+ lldb::TypeEnumMemberImplSP enum_member;
+ if (idx < GetSize())
+ enum_member = m_content[idx];
+ return enum_member;
+ }
+
+ size_t
+ GetSize()
+ {
+ return m_content.size();
+ }
+
+private:
+ std::vector<lldb::TypeEnumMemberImplSP> m_content;
+};
+
} // namespace lldb_private
#endif // liblldb_Type_h_
diff --git a/include/lldb/Symbol/UnwindPlan.h b/include/lldb/Symbol/UnwindPlan.h
index 6fc5ce042357..e1b146fe219e 100644
--- a/include/lldb/Symbol/UnwindPlan.h
+++ b/include/lldb/Symbol/UnwindPlan.h
@@ -365,6 +365,9 @@ public:
void
AppendRow (const RowSP& row_sp);
+ void
+ InsertRow (const RowSP& row_sp);
+
// Returns a pointer to the best row for the given offset into the function's instructions.
// If offset is -1 it indicates that the function start is unknown - the final row in the UnwindPlan is returned.
// In practice, the UnwindPlan for a function with no known start address will be the architectural default
diff --git a/include/lldb/Symbol/UnwindTable.h b/include/lldb/Symbol/UnwindTable.h
index 3a99eb463df4..3a89f9f1f3c6 100644
--- a/include/lldb/Symbol/UnwindTable.h
+++ b/include/lldb/Symbol/UnwindTable.h
@@ -13,7 +13,8 @@
#include <map>
-#include "lldb/lldb-private.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Host/Mutex.h"
namespace lldb_private {
@@ -42,6 +43,9 @@ public:
lldb::FuncUnwindersSP
GetUncachedFuncUnwindersContainingAddress (const Address& addr, SymbolContext &sc);
+ bool
+ GetArchitecture (lldb_private::ArchSpec &arch);
+
private:
void
Dump (Stream &s);
@@ -56,8 +60,7 @@ private:
collection m_unwinds;
bool m_initialized; // delay some initialization until ObjectFile is set up
-
- lldb::UnwindAssemblySP m_assembly_profiler;
+ Mutex m_mutex;
DWARFCallFrameInfo* m_eh_frame;
diff --git a/include/lldb/Symbol/VariableList.h b/include/lldb/Symbol/VariableList.h
index 08efd3d5b9a1..5f8f2a225650 100644
--- a/include/lldb/Symbol/VariableList.h
+++ b/include/lldb/Symbol/VariableList.h
@@ -60,10 +60,10 @@ public:
AppendVariablesIfUnique(VariableList &var_list);
// Returns the actual number of unique variables that were added to the
- // list. "total_matches" will get updated with the actualy number of
+ // list. "total_matches" will get updated with the actually number of
// matches that were found regardless of whether they were unique or not
// to allow for error conditions when nothing is found, versus conditions
- // where any varaibles that match "regex" were already in "var_list".
+ // where any variables that match "regex" were already in "var_list".
size_t
AppendVariablesIfUnique (const RegularExpression& regex,
VariableList &var_list,
diff --git a/include/lldb/Target/ABI.h b/include/lldb/Target/ABI.h
index cc6c46cf0ec9..8809c0047fa0 100644
--- a/include/lldb/Target/ABI.h
+++ b/include/lldb/Target/ABI.h
@@ -20,24 +20,58 @@
#include "llvm/ADT/ArrayRef.h"
+// forward define the llvm::Type class
+namespace llvm { class Type; }
+
namespace lldb_private {
class ABI :
public PluginInterface
{
public:
+
+ struct CallArgument
+ {
+ enum eType
+ {
+ HostPointer = 0, /* pointer to host data */
+ TargetValue , /* value is on the target or literal */
+ };
+ eType type; /* value of eType */
+ size_t size; /* size in bytes of this argument */
+ union {
+ lldb::addr_t value; /* literal value */
+ uint8_t *data; /* host data pointer */
+ };
+ };
+
virtual
~ABI();
virtual size_t
GetRedZoneSize () const = 0;
-
+
virtual bool
- PrepareTrivialCall (Thread &thread,
- lldb::addr_t sp,
- lldb::addr_t functionAddress,
- lldb::addr_t returnAddress,
- llvm::ArrayRef<lldb::addr_t> args) const = 0;
+ PrepareTrivialCall ( lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ llvm::ArrayRef<lldb::addr_t> args) const = 0;
+
+ // Prepare trivial call used from ThreadPlanFunctionCallGDB
+ // AD:
+ // . Because i don't want to change other ABI's this is not declared pure virtual.
+ // The dummy implementation will simply fail. Only HexagonABI will currently
+ // use this method.
+ // . Two PrepareTrivialCall's is not good design so perhaps this should be combined.
+ //
+ virtual bool
+ PrepareTrivialCall ( lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ llvm::Type &prototype,
+ llvm::ArrayRef<CallArgument> args) const;
virtual bool
GetArgumentValues (Thread &thread,
@@ -48,16 +82,26 @@ public:
ClangASTType &type,
bool persistent = true) const;
+ // specialized to work with llvm IR types
+ lldb::ValueObjectSP
+ GetReturnValueObject (Thread &thread,
+ llvm::Type &type,
+ bool persistent = true) const;
+
// Set the Return value object in the current frame as though a function with
virtual Error
SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) = 0;
protected:
// This is the method the ABI will call to actually calculate the return value.
- // Don't put it in a persistant value object, that will be done by the ABI::GetReturnValueObject.
+ // Don't put it in a persistent value object, that will be done by the ABI::GetReturnValueObject.
virtual lldb::ValueObjectSP
- GetReturnValueObjectImpl (Thread &thread,
- ClangASTType &type) const = 0;
+ GetReturnValueObjectImpl (Thread &thread, ClangASTType &ast_type) const = 0;
+
+ // specialized to work with llvm IR types
+ virtual lldb::ValueObjectSP
+ GetReturnValueObjectImpl( Thread &thread, llvm::Type &ir_type ) const;
+
public:
virtual bool
CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) = 0;
@@ -108,7 +152,6 @@ public:
virtual bool
FunctionCallsChangeCFA () = 0;
-
bool
GetRegisterInfoByName (const ConstString &name, RegisterInfo &info);
diff --git a/include/lldb/Target/CPPLanguageRuntime.h b/include/lldb/Target/CPPLanguageRuntime.h
index 98a4ab88cb25..daf8a67d2a9d 100644
--- a/include/lldb/Target/CPPLanguageRuntime.h
+++ b/include/lldb/Target/CPPLanguageRuntime.h
@@ -136,7 +136,7 @@ public:
static bool
StripNamespacesFromVariableName (const char *name, const char *&base_name_start, const char *&base_name_end);
- // in some cases, compilers will output different names for one same type. when tht happens, it might be impossible
+ // in some cases, compilers will output different names for one same type. when that happens, it might be impossible
// to construct SBType objects for a valid type, because the name that is available is not the same as the name that
// can be used as a search key in FindTypes(). the equivalents map here is meant to return possible alternative names
// for a type through which a search can be conducted. Currently, this is only enabled for C++ but can be extended
diff --git a/include/lldb/Target/ExecutionContext.h b/include/lldb/Target/ExecutionContext.h
index f825c2e72e6d..50f2beaf949b 100644
--- a/include/lldb/Target/ExecutionContext.h
+++ b/include/lldb/Target/ExecutionContext.h
@@ -18,10 +18,10 @@
/// variable value from a data section in one of the object files in
/// a target). There are two types of objects that hold onto execution
/// contexts: ExecutionContextRef and ExecutionContext. Both of these
-/// objects are deascribed below.
+/// objects are described below.
///
/// Not all objects in an ExectionContext objects will be valid. If you want
-/// to refer stronly (ExectionContext) or weakly (ExectionContextRef) to
+/// to refer strongly (ExectionContext) or weakly (ExectionContextRef) to
/// a process, then only the process and target references will be valid.
/// For threads, only the thread, process and target references will be
/// filled in. For frames, all of the objects will be filled in.
@@ -49,7 +49,7 @@ namespace lldb_private {
/// context that might change over time. For example, if an object wants
/// to refer to a stack frame, it should hold onto an ExecutionContextRef
/// to a frame object. The backing object that represents the stack frame
-/// might change over time and instaces of this object can track the logical
+/// might change over time and instances of this object can track the logical
/// object that refers to a frame even if it does change.
///
/// These objects also don't keep execution objects around longer than they
@@ -64,7 +64,7 @@ namespace lldb_private {
/// don't keep these objects around, they are safe to keep around.
///
/// The general rule of thumb is all long lived objects that want to
-/// refer to execution contexts should use ExecutionContextRef objcts.
+/// refer to execution contexts should use ExecutionContextRef objects.
/// The ExecutionContext class is used to temporarily get shared
/// pointers to any execution context objects that are still around
/// so they are guaranteed to exist during a function that requires the
@@ -89,7 +89,7 @@ public:
/// Construct using an ExecutionContext object that might be NULL.
///
/// If \a exe_ctx_ptr is valid, then make weak references to any
- /// valid objects in the ExecutionContext, othewise no weak
+ /// valid objects in the ExecutionContext, otherwise no weak
/// references to any execution context objects will be made.
//------------------------------------------------------------------
ExecutionContextRef (const ExecutionContext *exe_ctx_ptr);
@@ -104,7 +104,7 @@ public:
//------------------------------------------------------------------
/// Assignment operator
///
- /// Copy all weak refernces in \a rhs.
+ /// Copy all weak references in \a rhs.
//------------------------------------------------------------------
ExecutionContextRef &
operator =(const ExecutionContextRef &rhs);
@@ -112,7 +112,7 @@ public:
//------------------------------------------------------------------
/// Assignment operator from a ExecutionContext
///
- /// Make weak refernces to any stringly referenced objects in \a exe_ctx.
+ /// Make weak references to any strongly referenced objects in \a exe_ctx.
//------------------------------------------------------------------
ExecutionContextRef &
operator =(const ExecutionContext &exe_ctx);
@@ -129,13 +129,13 @@ public:
/// Construct using an execution context scope.
///
/// If the ExecutionContextScope object is valid and refers to a frame,
- /// make weak refernces too the frame, thread, process and target.
+ /// make weak references too the frame, thread, process and target.
/// If the ExecutionContextScope object is valid and refers to a thread,
- /// make weak refernces too the thread, process and target.
+ /// make weak references too the thread, process and target.
/// If the ExecutionContextScope object is valid and refers to a process,
- /// make weak refernces too the process and target.
+ /// make weak references too the process and target.
/// If the ExecutionContextScope object is valid and refers to a target,
- /// make weak refernces too the target.
+ /// make weak references too the target.
//------------------------------------------------------------------
ExecutionContextRef (ExecutionContextScope *exe_scope);
@@ -143,13 +143,13 @@ public:
/// Construct using an execution context scope.
///
/// If the ExecutionContextScope object refers to a frame,
- /// make weak refernces too the frame, thread, process and target.
+ /// make weak references too the frame, thread, process and target.
/// If the ExecutionContextScope object refers to a thread,
- /// make weak refernces too the thread, process and target.
+ /// make weak references too the thread, process and target.
/// If the ExecutionContextScope object refers to a process,
- /// make weak refernces too the process and target.
+ /// make weak references too the process and target.
/// If the ExecutionContextScope object refers to a target,
- /// make weak refernces too the target.
+ /// make weak references too the target.
//------------------------------------------------------------------
ExecutionContextRef (ExecutionContextScope &exe_scope);
@@ -302,8 +302,8 @@ public:
//------------------------------------------------------------------
/// Returns true if this object has a weak reference to a thread.
- /// The return value is only an indication of wether this object has
- /// a weak reference and does not indicate wether the weak rerference
+ /// The return value is only an indication of whether this object has
+ /// a weak reference and does not indicate whether the weak reference
/// is valid or not.
//------------------------------------------------------------------
bool
@@ -314,8 +314,8 @@ public:
//------------------------------------------------------------------
/// Returns true if this object has a weak reference to a frame.
- /// The return value is only an indication of wether this object has
- /// a weak reference and does not indicate wether the weak rerference
+ /// The return value is only an indication of whether this object has
+ /// a weak reference and does not indicate whether the weak reference
/// is valid or not.
//------------------------------------------------------------------
bool
diff --git a/include/lldb/Target/ExecutionContextScope.h b/include/lldb/Target/ExecutionContextScope.h
index 7ba40971af2c..4a1b17d5a114 100644
--- a/include/lldb/Target/ExecutionContextScope.h
+++ b/include/lldb/Target/ExecutionContextScope.h
@@ -29,7 +29,7 @@ namespace lldb_private {
/// ExecutionContext object in the object state. Examples of these
/// objects include: Process, Thread, RegisterContext and StackFrame.
///
-/// Bbjects can contain a valid pointer to an instance of this so they
+/// Objects can contain a valid pointer to an instance of this so they
/// can reconstruct the execution context.
///
/// Objects that adhere to this protocol can reconstruct enough of a
diff --git a/include/lldb/Target/FileAction.h b/include/lldb/Target/FileAction.h
new file mode 100644
index 000000000000..db84c0ef468c
--- /dev/null
+++ b/include/lldb/Target/FileAction.h
@@ -0,0 +1,68 @@
+//===-- ProcessLaunchInfo.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_Target_FileAction_h
+#define liblldb_Target_FileAction_h
+
+#include <string>
+
+namespace lldb_private
+{
+
+class FileAction
+{
+ public:
+ enum Action
+ {
+ eFileActionNone,
+ eFileActionClose,
+ eFileActionDuplicate,
+ eFileActionOpen
+ };
+
+ FileAction();
+
+ void Clear();
+
+ bool Close(int fd);
+
+ bool Duplicate(int fd, int dup_fd);
+
+ bool Open(int fd, const char *path, bool read, bool write);
+
+ int
+ GetFD() const
+ {
+ return m_fd;
+ }
+
+ Action
+ GetAction() const
+ {
+ return m_action;
+ }
+
+ int
+ GetActionArgument() const
+ {
+ return m_arg;
+ }
+
+ const char *GetPath() const;
+
+ protected:
+ Action m_action; // The action for this file
+ int m_fd; // An existing file descriptor
+ int m_arg; // oflag for eFileActionOpen*, dup_fd for eFileActionDuplicate
+ std::string m_path; // A file path to use for opening after fork or posix_spawn
+};
+
+} // namespace lldb_private
+
+#endif
diff --git a/include/lldb/Target/JITLoader.h b/include/lldb/Target/JITLoader.h
new file mode 100644
index 000000000000..c15ae5a876f1
--- /dev/null
+++ b/include/lldb/Target/JITLoader.h
@@ -0,0 +1,90 @@
+//===-- JITLoader.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_JITLoader_h_
+#define liblldb_JITLoader_h_
+
+#include <vector>
+
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Target/JITLoaderList.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class JITLoader JITLoader.h "lldb/Target/JITLoader.h"
+/// @brief A plug-in interface definition class for JIT loaders.
+///
+/// Plugins of this kind listen for code generated at runtime in the
+/// target. They are very similar to dynamic loader, with the difference
+/// that they do not have information about the target's dyld and
+/// that there may be multiple JITLoader plugins per process, while
+/// there is at most one DynamicLoader.
+//----------------------------------------------------------------------
+class JITLoader :
+ public PluginInterface
+{
+public:
+ //------------------------------------------------------------------
+ /// Find a JIT loader plugin for a given process.
+ ///
+ /// Scans the installed DynamicLoader plug-ins and tries to find
+ /// all applicable instances for the current process.
+ ///
+ /// @param[in] process
+ /// The process for which to try and locate a JIT loader
+ /// plug-in instance.
+ ///
+ //------------------------------------------------------------------
+ static void
+ LoadPlugins (Process *process, lldb_private::JITLoaderList &list);
+
+ //------------------------------------------------------------------
+ /// Construct with a process.
+ //------------------------------------------------------------------
+ JITLoader (Process *process);
+
+ virtual
+ ~JITLoader ();
+
+ //------------------------------------------------------------------
+ /// Called after attaching a process.
+ ///
+ /// Allow JITLoader plug-ins to execute some code after
+ /// attaching to a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidAttach () = 0;
+
+ //------------------------------------------------------------------
+ /// Called after launching a process.
+ ///
+ /// Allow JITLoader plug-ins to execute some code after
+ /// the process has stopped for the first time on launch.
+ //------------------------------------------------------------------
+ virtual void
+ DidLaunch () = 0;
+
+ //------------------------------------------------------------------
+ /// Called after a new shared object has been loaded so that it can
+ /// be probed for JIT entry point hooks.
+ //------------------------------------------------------------------
+ virtual void
+ ModulesDidLoad (lldb_private::ModuleList &module_list) = 0;
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ Process* m_process;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_JITLoader_h_
diff --git a/include/lldb/Target/JITLoaderList.h b/include/lldb/Target/JITLoaderList.h
new file mode 100644
index 000000000000..f933a61e9952
--- /dev/null
+++ b/include/lldb/Target/JITLoaderList.h
@@ -0,0 +1,60 @@
+//===-- JITLoaderList.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_JITLoaderList_h_
+#define liblldb_JITLoaderList_h_
+
+#include <vector>
+
+#include "lldb/lldb-forward.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class JITLoaderList JITLoaderList.h "lldb/Target/JITLoaderList.h"
+///
+/// Class used by the Process to hold a list of its JITLoaders.
+//----------------------------------------------------------------------
+class JITLoaderList
+{
+public:
+
+ JITLoaderList();
+ ~JITLoaderList();
+
+ void
+ Append (const lldb::JITLoaderSP &jit_loader_sp);
+
+ void
+ Remove (const lldb::JITLoaderSP &jit_loader_sp);
+
+ size_t
+ GetSize() const;
+
+ lldb::JITLoaderSP
+ GetLoaderAtIndex (size_t idx);
+
+ void
+ DidLaunch();
+
+ void
+ DidAttach();
+
+ void
+ ModulesDidLoad (ModuleList &module_list);
+
+private:
+ std::vector<lldb::JITLoaderSP> m_jit_loaders_vec;
+ lldb_private::Mutex m_jit_loaders_mutex;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_JITLoaderList_h_
diff --git a/include/lldb/Target/MemoryRegionInfo.h b/include/lldb/Target/MemoryRegionInfo.h
new file mode 100644
index 000000000000..0726ad15e876
--- /dev/null
+++ b/include/lldb/Target/MemoryRegionInfo.h
@@ -0,0 +1,104 @@
+//===-- MemoryRegionInfo.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_MemoryRegionInfo_h
+#define lldb_MemoryRegionInfo_h
+
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Utility/Range.h"
+
+namespace lldb_private
+{
+ class MemoryRegionInfo
+ {
+ public:
+ typedef Range<lldb::addr_t, lldb::addr_t> RangeType;
+
+ enum OptionalBool {
+ eDontKnow = -1,
+ eNo = 0,
+ eYes = 1
+ };
+
+ MemoryRegionInfo () :
+ m_range (),
+ m_read (eDontKnow),
+ m_write (eDontKnow),
+ m_execute (eDontKnow)
+ {
+ }
+
+ ~MemoryRegionInfo ()
+ {
+ }
+
+ RangeType &
+ GetRange()
+ {
+ return m_range;
+ }
+
+ void
+ Clear()
+ {
+ m_range.Clear();
+ m_read = m_write = m_execute = eDontKnow;
+ }
+
+ const RangeType &
+ GetRange() const
+ {
+ return m_range;
+ }
+
+ OptionalBool
+ GetReadable () const
+ {
+ return m_read;
+ }
+
+ OptionalBool
+ GetWritable () const
+ {
+ return m_write;
+ }
+
+ OptionalBool
+ GetExecutable () const
+ {
+ return m_execute;
+ }
+
+ void
+ SetReadable (OptionalBool val)
+ {
+ m_read = val;
+ }
+
+ void
+ SetWritable (OptionalBool val)
+ {
+ m_write = val;
+ }
+
+ void
+ SetExecutable (OptionalBool val)
+ {
+ m_execute = val;
+ }
+
+ protected:
+ RangeType m_range;
+ OptionalBool m_read;
+ OptionalBool m_write;
+ OptionalBool m_execute;
+ };
+}
+
+#endif // #ifndef lldb_MemoryRegionInfo_h
diff --git a/include/lldb/Target/NativeRegisterContext.h b/include/lldb/Target/NativeRegisterContext.h
new file mode 100644
index 000000000000..fa4ab013f234
--- /dev/null
+++ b/include/lldb/Target/NativeRegisterContext.h
@@ -0,0 +1,190 @@
+//===-- NativeRegisterContext.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_NativeRegisterContext_h_
+#define liblldb_NativeRegisterContext_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class NativeThreadProtocol;
+
+class NativeRegisterContext:
+ public std::enable_shared_from_this<NativeRegisterContext>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ NativeRegisterContext (NativeThreadProtocol &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~NativeRegisterContext ();
+
+ // void
+ // InvalidateIfNeeded (bool force);
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ // virtual void
+ // InvalidateAllRegisters () = 0;
+
+ virtual uint32_t
+ GetRegisterCount () const = 0;
+
+ virtual const RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t reg) const = 0;
+
+ const char *
+ GetRegisterSetNameForRegisterAtIndex (uint32_t reg_index) const;
+
+ virtual uint32_t
+ GetRegisterSetCount () const = 0;
+
+ virtual const RegisterSet *
+ GetRegisterSet (uint32_t set_index) const = 0;
+
+ virtual Error
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value) = 0;
+
+ virtual Error
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value) = 0;
+
+ virtual Error
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp) = 0;
+
+ virtual Error
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) = 0;
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const;
+
+ //------------------------------------------------------------------
+ // Subclasses can override these functions if desired
+ //------------------------------------------------------------------
+ virtual uint32_t
+ NumSupportedHardwareBreakpoints ();
+
+ virtual uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size);
+
+ virtual bool
+ ClearHardwareBreakpoint (uint32_t hw_idx);
+
+ virtual uint32_t
+ NumSupportedHardwareWatchpoints ();
+
+ virtual uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags);
+
+ virtual bool
+ ClearHardwareWatchpoint (uint32_t hw_index);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ virtual Error
+ ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, lldb::addr_t src_len, RegisterValue &reg_value);
+
+ virtual Error
+ WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, lldb::addr_t dst_len, const RegisterValue &reg_value);
+
+ //------------------------------------------------------------------
+ // Subclasses should not override these
+ //------------------------------------------------------------------
+ virtual lldb::tid_t
+ GetThreadID() const;
+
+ virtual NativeThreadProtocol &
+ GetThread ()
+ {
+ return m_thread;
+ }
+
+ const RegisterInfo *
+ GetRegisterInfoByName (const char *reg_name, uint32_t start_idx = 0);
+
+ const RegisterInfo *
+ GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num);
+
+ lldb::addr_t
+ GetPC (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+
+ Error
+ SetPC (lldb::addr_t pc);
+
+ lldb::addr_t
+ GetSP (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+
+ Error
+ SetSP (lldb::addr_t sp);
+
+ lldb::addr_t
+ GetFP (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+
+ Error
+ SetFP (lldb::addr_t fp);
+
+ const char *
+ GetRegisterName (uint32_t reg);
+
+ lldb::addr_t
+ GetReturnAddress (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+
+ lldb::addr_t
+ GetFlags (lldb::addr_t fail_value = 0);
+
+ lldb::addr_t
+ ReadRegisterAsUnsigned (uint32_t reg, lldb::addr_t fail_value);
+
+ lldb::addr_t
+ ReadRegisterAsUnsigned (const RegisterInfo *reg_info, lldb::addr_t fail_value);
+
+ Error
+ WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval);
+
+ Error
+ WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval);
+
+ // uint32_t
+ // GetStopID () const
+ // {
+ // return m_stop_id;
+ // }
+
+ // void
+ // SetStopID (uint32_t stop_id)
+ // {
+ // m_stop_id = stop_id;
+ // }
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from RegisterContext can see and modify these
+ //------------------------------------------------------------------
+ NativeThreadProtocol &m_thread; // The thread that this register context belongs to.
+ uint32_t m_concrete_frame_idx; // The concrete frame index for this register context
+ // uint32_t m_stop_id; // The stop ID that any data in this context is valid for
+
+private:
+ //------------------------------------------------------------------
+ // For RegisterContext only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (NativeRegisterContext);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_NativeRegisterContext_h_
diff --git a/include/lldb/Target/NativeRegisterContextRegisterInfo.h b/include/lldb/Target/NativeRegisterContextRegisterInfo.h
new file mode 100644
index 000000000000..5631005ca56e
--- /dev/null
+++ b/include/lldb/Target/NativeRegisterContextRegisterInfo.h
@@ -0,0 +1,44 @@
+//===-- NativeRegisterContextRegisterInfo.h ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextRegisterInfo_h
+#define lldb_NativeRegisterContextRegisterInfo_h
+
+#include <memory>
+
+#include "NativeRegisterContext.h"
+#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+
+namespace lldb_private
+{
+ class NativeRegisterContextRegisterInfo: public NativeRegisterContext
+ {
+ public:
+ ///
+ /// Construct a NativeRegisterContextRegisterInfo, taking ownership
+ /// of the register_info_interface pointer.
+ ///
+ NativeRegisterContextRegisterInfo (NativeThreadProtocol &thread,
+ uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info_interface);
+
+ uint32_t
+ GetRegisterCount () const override;
+
+ const RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t reg_index) const override;
+
+ const RegisterInfoInterface&
+ GetRegisterInfoInterface () const;
+
+ private:
+ std::unique_ptr<RegisterInfoInterface> m_register_info_interface_up;
+ };
+}
+#endif
diff --git a/include/lldb/Target/ObjCLanguageRuntime.h b/include/lldb/Target/ObjCLanguageRuntime.h
index 7bac57256444..12254f942e42 100644
--- a/include/lldb/Target/ObjCLanguageRuntime.h
+++ b/include/lldb/Target/ObjCLanguageRuntime.h
@@ -20,6 +20,7 @@
// Project includes
#include "lldb/lldb-private.h"
#include "lldb/Core/PluginInterface.h"
+#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/TypeVendor.h"
#include "lldb/Target/LanguageRuntime.h"
@@ -221,7 +222,7 @@ public:
Describe (std::function <void (ObjCISA)> const &superclass_func,
std::function <bool (const char*, const char*)> const &instance_method_func,
std::function <bool (const char*, const char*)> const &class_method_func,
- std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func)
+ std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func) const
{
return false;
}
@@ -238,6 +239,25 @@ public:
m_type_wp = type_sp;
}
+ struct iVarDescriptor {
+ ConstString m_name;
+ ClangASTType m_type;
+ uint64_t m_size;
+ int32_t m_offset;
+ };
+
+ virtual size_t
+ GetNumIVars ()
+ {
+ return 0;
+ }
+
+ virtual iVarDescriptor
+ GetIVarAtIndex (size_t idx)
+ {
+ return iVarDescriptor();
+ }
+
protected:
bool
IsPointerValid (lldb::addr_t value,
@@ -252,6 +272,25 @@ public:
lldb::TypeWP m_type_wp;
};
+ class EncodingToType
+ {
+ public:
+ virtual ClangASTType RealizeType (ClangASTContext& ast_ctx, const char* name, bool allow_unknownanytype);
+ virtual ClangASTType RealizeType (const char* name, bool allow_unknownanytype);
+
+ virtual ClangASTType RealizeType (clang::ASTContext& ast_ctx, const char* name, bool allow_unknownanytype) = 0;
+
+ virtual ~EncodingToType();
+
+ protected:
+ std::unique_ptr<ClangASTContext> m_scratch_ast_ctx_ap;
+ };
+
+ typedef std::shared_ptr<EncodingToType> EncodingToTypeSP;
+
+ virtual EncodingToTypeSP
+ GetEncodingToType ();
+
virtual ClassDescriptorSP
GetClassDescriptor (ValueObject& in_value);
diff --git a/include/lldb/Target/PathMappingList.h b/include/lldb/Target/PathMappingList.h
index b5bcbbfd768f..17185cb68495 100644
--- a/include/lldb/Target/PathMappingList.h
+++ b/include/lldb/Target/PathMappingList.h
@@ -78,7 +78,7 @@ public:
bool notify);
bool
- Remove (off_t index, bool notify);
+ Remove (size_t index, bool notify);
bool
Remove (const ConstString &path, bool notify);
diff --git a/include/lldb/Target/Platform.h b/include/lldb/Target/Platform.h
index 80011fd120de..e3d6abe3f398 100644
--- a/include/lldb/Target/Platform.h
+++ b/include/lldb/Target/Platform.h
@@ -18,6 +18,7 @@
// Other libraries and framework includes
// Project includes
+#include "lldb/lldb-private-forward.h"
#include "lldb/lldb-public.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/ConstString.h"
@@ -25,6 +26,10 @@
#include "lldb/Interpreter/Options.h"
#include "lldb/Host/Mutex.h"
+// TODO pull NativeDelegate class out of NativeProcessProtocol so we
+// can just forward ref the NativeDelegate rather than include it here.
+#include "../../../source/Host/common/NativeProcessProtocol.h"
+
namespace lldb_private {
//----------------------------------------------------------------------
@@ -174,13 +179,13 @@ namespace lldb_private {
/// m_arch - The architecture we are looking for when resolving
/// the symbol file.
/// m_uuid - The UUID of the executable and symbol file. This
- /// can often be used to match up an exectuable with
+ /// can often be used to match up an executable with
/// a symbol file, or resolve an symbol file in a
/// symbol file bundle.
///
/// @param[out] sym_file
/// The resolved symbol file spec if the returned error
- /// indicates succes.
+ /// indicates success.
///
/// @return
/// Returns an error that describes success or failure.
@@ -215,7 +220,7 @@ namespace lldb_private {
bool
GetOSKernelDescription (std::string &s);
- // Returns the the name of the platform
+ // Returns the name of the platform
ConstString
GetName ();
@@ -241,7 +246,7 @@ namespace lldb_private {
//
// Remote classes must be connected for this to succeed. Local
// subclasses don't need to override this function as it will just
- // call the Host::GetOSVersion().
+ // call the HostInfo::GetOSVersion().
//------------------------------------------------------------------
virtual bool
GetRemoteOSVersion ()
@@ -326,7 +331,8 @@ namespace lldb_private {
//----------------------------------------------------------------------
virtual FileSpecList
LocateExecutableScriptingResources (Target *target,
- Module &module);
+ Module &module,
+ Stream* feedback_stream);
virtual Error
GetSharedModule (const ModuleSpec &module_spec,
@@ -349,7 +355,7 @@ namespace lldb_private {
/// A zero based architecture index
///
/// @param[out] arch
- /// A copy of the archgitecture at index if the return value is
+ /// A copy of the architecture at index if the return value is
/// \b true.
///
/// @return
@@ -413,7 +419,7 @@ namespace lldb_private {
/// attempt to attach to the process with the process ID of \a pid.
/// The platform subclass should return an appropriate ProcessSP
/// subclass that is attached to the process, or an empty shared
- /// pointer with an appriopriate error.
+ /// pointer with an appropriate error.
///
/// @param[in] pid
/// The process ID that we should attempt to attach to.
@@ -422,7 +428,7 @@ namespace lldb_private {
/// An appropriate ProcessSP containing a valid shared pointer
/// to the default Process subclass for the platform that is
/// attached to the process, or an empty shared pointer with an
- /// appriopriate error fill into the \a error object.
+ /// appropriate error fill into the \a error object.
//------------------------------------------------------------------
virtual lldb::ProcessSP
Attach (ProcessAttachInfo &attach_info,
@@ -858,13 +864,72 @@ namespace lldb_private {
virtual const std::vector<ConstString> &
GetTrapHandlerSymbolNames ();
+ //------------------------------------------------------------------
+ /// Launch a process for debugging.
+ ///
+ /// This differs from Launch in that it returns a NativeProcessProtocol.
+ /// Currently used by lldb-gdbserver.
+ ///
+ /// @param[in] launch_info
+ /// Information required to launch the process.
+ ///
+ /// @param[in] native_delegate
+ /// The delegate that will receive messages regarding the
+ /// inferior. Must outlive the NativeProcessProtocol
+ /// instance.
+ ///
+ /// @param[out] process_sp
+ /// On successful return from the method, this parameter
+ /// contains the shared pointer to the
+ /// NativeProcessProtocol that can be used to manipulate
+ /// the native process.
+ ///
+ /// @return
+ /// An error object indicating if the operation succeeded,
+ /// and if not, what error occurred.
+ //------------------------------------------------------------------
+ virtual Error
+ LaunchNativeProcess (
+ ProcessLaunchInfo &launch_info,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp);
+
+ //------------------------------------------------------------------
+ /// Attach to an existing process on the given platform.
+ ///
+ /// This method differs from Attach() in that it returns a
+ /// NativeProcessProtocol. Currently this is used by lldb-gdbserver.
+ ///
+ /// @param[in] pid
+ /// pid of the process locatable by the platform.
+ ///
+ /// @param[in] native_delegate
+ /// The delegate that will receive messages regarding the
+ /// inferior. Must outlive the NativeProcessProtocol
+ /// instance.
+ ///
+ /// @param[out] process_sp
+ /// On successful return from the method, this parameter
+ /// contains the shared pointer to the
+ /// NativeProcessProtocol that can be used to manipulate
+ /// the native process.
+ ///
+ /// @return
+ /// An error object indicating if the operation succeeded,
+ /// and if not, what error occurred.
+ //------------------------------------------------------------------
+ virtual Error
+ AttachNativeProcess (lldb::pid_t pid,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp);
+
protected:
bool m_is_host;
// Set to true when we are able to actually set the OS version while
// being connected. For remote platforms, we might set the version ahead
// of time before we actually connect and this version might change when
// we actually connect to a remote platform. For the host platform this
- // will be set to the once we call Host::GetOSVersion().
+ // will be set to the once we call HostInfo::GetOSVersion().
bool m_os_version_set_while_connected;
bool m_system_arch_set_while_connected;
ConstString m_sdk_sysroot; // the root location of where the SDK files are all located
@@ -892,6 +957,7 @@ namespace lldb_private {
std::string m_local_cache_directory;
std::vector<ConstString> m_trap_handlers;
bool m_calculated_trap_handlers;
+ Mutex m_trap_handler_mutex;
//------------------------------------------------------------------
/// Ask the Platform subclass to fill in the list of trap handler names
diff --git a/include/lldb/Target/Process.h b/include/lldb/Target/Process.h
index b74347d37e68..641707c58deb 100644
--- a/include/lldb/Target/Process.h
+++ b/include/lldb/Target/Process.h
@@ -42,7 +42,11 @@
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/Options.h"
#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/JITLoaderList.h"
#include "lldb/Target/Memory.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/ProcessInfo.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Target/QueueList.h"
#include "lldb/Target/ThreadList.h"
#include "lldb/Target/UnixSignals.h"
@@ -104,232 +108,6 @@ public:
typedef std::shared_ptr<ProcessProperties> ProcessPropertiesSP;
//----------------------------------------------------------------------
-// ProcessInfo
-//
-// A base class for information for a process. This can be used to fill
-// out information for a process prior to launching it, or it can be
-// used for an instance of a process and can be filled in with the
-// existing values for that process.
-//----------------------------------------------------------------------
-class ProcessInfo
-{
-public:
- ProcessInfo () :
- m_executable (),
- m_arguments (),
- m_environment (),
- m_uid (UINT32_MAX),
- m_gid (UINT32_MAX),
- m_arch(),
- m_pid (LLDB_INVALID_PROCESS_ID)
- {
- }
-
- ProcessInfo (const char *name,
- const ArchSpec &arch,
- lldb::pid_t pid) :
- m_executable (name, false),
- m_arguments (),
- m_environment(),
- m_uid (UINT32_MAX),
- m_gid (UINT32_MAX),
- m_arch (arch),
- m_pid (pid)
- {
- }
-
- void
- Clear ()
- {
- m_executable.Clear();
- m_arguments.Clear();
- m_environment.Clear();
- m_uid = UINT32_MAX;
- m_gid = UINT32_MAX;
- m_arch.Clear();
- m_pid = LLDB_INVALID_PROCESS_ID;
- }
-
- const char *
- GetName() const
- {
- return m_executable.GetFilename().GetCString();
- }
-
- size_t
- GetNameLength() const
- {
- return m_executable.GetFilename().GetLength();
- }
-
- FileSpec &
- GetExecutableFile ()
- {
- return m_executable;
- }
-
- void
- SetExecutableFile (const FileSpec &exe_file, bool add_exe_file_as_first_arg)
- {
- if (exe_file)
- {
- m_executable = exe_file;
- if (add_exe_file_as_first_arg)
- {
- char filename[PATH_MAX];
- if (exe_file.GetPath(filename, sizeof(filename)))
- m_arguments.InsertArgumentAtIndex (0, filename);
- }
- }
- else
- {
- m_executable.Clear();
- }
- }
-
- const FileSpec &
- GetExecutableFile () const
- {
- return m_executable;
- }
-
- uint32_t
- GetUserID() const
- {
- return m_uid;
- }
-
- uint32_t
- GetGroupID() const
- {
- return m_gid;
- }
-
- bool
- UserIDIsValid () const
- {
- return m_uid != UINT32_MAX;
- }
-
- bool
- GroupIDIsValid () const
- {
- return m_gid != UINT32_MAX;
- }
-
- void
- SetUserID (uint32_t uid)
- {
- m_uid = uid;
- }
-
- void
- SetGroupID (uint32_t gid)
- {
- m_gid = gid;
- }
-
- ArchSpec &
- GetArchitecture ()
- {
- return m_arch;
- }
-
- const ArchSpec &
- GetArchitecture () const
- {
- return m_arch;
- }
-
- void
- SetArchitecture (ArchSpec arch)
- {
- m_arch = arch;
- }
-
- lldb::pid_t
- GetProcessID () const
- {
- return m_pid;
- }
-
- void
- SetProcessID (lldb::pid_t pid)
- {
- m_pid = pid;
- }
-
- bool
- ProcessIDIsValid() const
- {
- return m_pid != LLDB_INVALID_PROCESS_ID;
- }
-
- void
- Dump (Stream &s, Platform *platform) const;
-
- Args &
- GetArguments ()
- {
- return m_arguments;
- }
-
- const Args &
- GetArguments () const
- {
- return m_arguments;
- }
-
- const char *
- GetArg0 () const
- {
- if (m_arg0.empty())
- return NULL;
- return m_arg0.c_str();
- }
-
- void
- SetArg0 (const char *arg)
- {
- if (arg && arg[0])
- m_arg0 = arg;
- else
- m_arg0.clear();
- }
-
- void
- SetArguments (const Args& args, bool first_arg_is_executable);
-
- void
- SetArguments (char const **argv, bool first_arg_is_executable);
-
- Args &
- GetEnvironmentEntries ()
- {
- return m_environment;
- }
-
- const Args &
- GetEnvironmentEntries () const
- {
- return m_environment;
- }
-
-protected:
- FileSpec m_executable;
- std::string m_arg0; // argv[0] if supported. If empty, then use m_executable.
- // Not all process plug-ins support specifying an argv[0]
- // that differs from the resolved platform executable
- // (which is in m_executable)
- Args m_arguments; // All program arguments except argv[0]
- Args m_environment;
- uint32_t m_uid;
- uint32_t m_gid;
- ArchSpec m_arch;
- lldb::pid_t m_pid;
-};
-
-//----------------------------------------------------------------------
// ProcessInstanceInfo
//
// Describes an existing process and any discoverable information that
@@ -434,445 +212,10 @@ protected:
lldb::pid_t m_parent_pid;
};
-
//----------------------------------------------------------------------
-// ProcessLaunchInfo
+// ProcessAttachInfo
//
-// Describes any information that is required to launch a process.
-//----------------------------------------------------------------------
-
-class ProcessLaunchInfo : public ProcessInfo
-{
-public:
-
- class FileAction
- {
- public:
- enum Action
- {
- eFileActionNone,
- eFileActionClose,
- eFileActionDuplicate,
- eFileActionOpen
- };
-
-
- FileAction () :
- m_action (eFileActionNone),
- m_fd (-1),
- m_arg (-1),
- m_path ()
- {
- }
-
- void
- Clear()
- {
- m_action = eFileActionNone;
- m_fd = -1;
- m_arg = -1;
- m_path.clear();
- }
-
- bool
- Close (int fd);
-
- bool
- Duplicate (int fd, int dup_fd);
-
- bool
- Open (int fd, const char *path, bool read, bool write);
-
-#ifndef LLDB_DISABLE_POSIX
- static bool
- AddPosixSpawnFileAction (void *file_actions,
- const FileAction *info,
- Log *log,
- Error& error);
-#endif
-
- int
- GetFD () const
- {
- return m_fd;
- }
-
- Action
- GetAction () const
- {
- return m_action;
- }
-
- int
- GetActionArgument () const
- {
- return m_arg;
- }
-
- const char *
- GetPath () const
- {
- if (m_path.empty())
- return NULL;
- return m_path.c_str();
- }
-
- protected:
- Action m_action; // The action for this file
- int m_fd; // An existing file descriptor
- int m_arg; // oflag for eFileActionOpen*, dup_fd for eFileActionDuplicate
- std::string m_path; // A file path to use for opening after fork or posix_spawn
- };
-
- ProcessLaunchInfo () :
- ProcessInfo(),
- m_working_dir (),
- m_plugin_name (),
- m_shell (),
- m_flags (0),
- m_file_actions (),
- m_pty (),
- m_resume_count (0),
- m_monitor_callback (NULL),
- m_monitor_callback_baton (NULL),
- m_monitor_signals (false),
- m_hijack_listener_sp ()
- {
- }
-
- ProcessLaunchInfo (const char *stdin_path,
- const char *stdout_path,
- const char *stderr_path,
- const char *working_directory,
- uint32_t launch_flags) :
- ProcessInfo(),
- m_working_dir (),
- m_plugin_name (),
- m_shell (),
- m_flags (launch_flags),
- m_file_actions (),
- m_pty (),
- m_resume_count (0),
- m_monitor_callback (NULL),
- m_monitor_callback_baton (NULL),
- m_monitor_signals (false),
- m_hijack_listener_sp ()
- {
- if (stdin_path)
- {
- ProcessLaunchInfo::FileAction file_action;
- const bool read = true;
- const bool write = false;
- if (file_action.Open(STDIN_FILENO, stdin_path, read, write))
- AppendFileAction (file_action);
- }
- if (stdout_path)
- {
- ProcessLaunchInfo::FileAction file_action;
- const bool read = false;
- const bool write = true;
- if (file_action.Open(STDOUT_FILENO, stdout_path, read, write))
- AppendFileAction (file_action);
- }
- if (stderr_path)
- {
- ProcessLaunchInfo::FileAction file_action;
- const bool read = false;
- const bool write = true;
- if (file_action.Open(STDERR_FILENO, stderr_path, read, write))
- AppendFileAction (file_action);
- }
- if (working_directory)
- SetWorkingDirectory(working_directory);
- }
-
- void
- AppendFileAction (const FileAction &info)
- {
- m_file_actions.push_back(info);
- }
-
- bool
- AppendCloseFileAction (int fd)
- {
- FileAction file_action;
- if (file_action.Close (fd))
- {
- AppendFileAction (file_action);
- return true;
- }
- return false;
- }
-
- bool
- AppendDuplicateFileAction (int fd, int dup_fd)
- {
- FileAction file_action;
- if (file_action.Duplicate (fd, dup_fd))
- {
- AppendFileAction (file_action);
- return true;
- }
- return false;
- }
-
- bool
- AppendOpenFileAction (int fd, const char *path, bool read, bool write)
- {
- FileAction file_action;
- if (file_action.Open (fd, path, read, write))
- {
- AppendFileAction (file_action);
- return true;
- }
- return false;
- }
-
- bool
- AppendSuppressFileAction (int fd, bool read, bool write)
- {
- FileAction file_action;
- if (file_action.Open (fd, "/dev/null", read, write))
- {
- AppendFileAction (file_action);
- return true;
- }
- return false;
- }
-
- void
- FinalizeFileActions (Target *target,
- bool default_to_use_pty);
-
- size_t
- GetNumFileActions () const
- {
- return m_file_actions.size();
- }
-
- const FileAction *
- GetFileActionAtIndex (size_t idx) const
- {
- if (idx < m_file_actions.size())
- return &m_file_actions[idx];
- return NULL;
- }
-
- const FileAction *
- GetFileActionForFD (int fd) const
- {
- for (size_t idx=0, count=m_file_actions.size(); idx < count; ++idx)
- {
- if (m_file_actions[idx].GetFD () == fd)
- return &m_file_actions[idx];
- }
- return NULL;
- }
-
- Flags &
- GetFlags ()
- {
- return m_flags;
- }
-
- const Flags &
- GetFlags () const
- {
- return m_flags;
- }
-
- const char *
- GetWorkingDirectory () const
- {
- if (m_working_dir.empty())
- return NULL;
- return m_working_dir.c_str();
- }
-
- void
- SetWorkingDirectory (const char *working_dir)
- {
- if (working_dir && working_dir[0])
- m_working_dir.assign (working_dir);
- else
- m_working_dir.clear();
- }
-
- void
- SwapWorkingDirectory (std::string &working_dir)
- {
- m_working_dir.swap (working_dir);
- }
-
-
- const char *
- GetProcessPluginName () const
- {
- if (m_plugin_name.empty())
- return NULL;
- return m_plugin_name.c_str();
- }
-
- void
- SetProcessPluginName (const char *plugin)
- {
- if (plugin && plugin[0])
- m_plugin_name.assign (plugin);
- else
- m_plugin_name.clear();
- }
-
- const char *
- GetShell () const
- {
- if (m_shell.empty())
- return NULL;
- return m_shell.c_str();
- }
-
- void
- SetShell (const char * path)
- {
- if (path && path[0])
- {
- m_shell.assign (path);
- m_flags.Set (lldb::eLaunchFlagLaunchInShell);
- }
- else
- {
- m_shell.clear();
- m_flags.Clear (lldb::eLaunchFlagLaunchInShell);
- }
- }
-
- uint32_t
- GetResumeCount () const
- {
- return m_resume_count;
- }
-
- void
- SetResumeCount (uint32_t c)
- {
- m_resume_count = c;
- }
-
- bool
- GetLaunchInSeparateProcessGroup ()
- {
- return m_flags.Test(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
- }
-
- void
- SetLaunchInSeparateProcessGroup (bool separate)
- {
- if (separate)
- m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
- else
- m_flags.Clear (lldb::eLaunchFlagLaunchInSeparateProcessGroup);
-
- }
-
- void
- Clear ()
- {
- ProcessInfo::Clear();
- m_working_dir.clear();
- m_plugin_name.clear();
- m_shell.clear();
- m_flags.Clear();
- m_file_actions.clear();
- m_resume_count = 0;
- m_hijack_listener_sp.reset();
- }
-
- bool
- ConvertArgumentsForLaunchingInShell (Error &error,
- bool localhost,
- bool will_debug,
- bool first_arg_is_full_shell_command,
- int32_t num_resumes);
-
- void
- SetMonitorProcessCallback (Host::MonitorChildProcessCallback callback,
- void *baton,
- bool monitor_signals)
- {
- m_monitor_callback = callback;
- m_monitor_callback_baton = baton;
- m_monitor_signals = monitor_signals;
- }
-
- Host::MonitorChildProcessCallback
- GetMonitorProcessCallback ()
- {
- return m_monitor_callback;
- }
-
- const void*
- GetMonitorProcessBaton () const
- {
- return m_monitor_callback_baton;
- }
-
- // If the LaunchInfo has a monitor callback, then arrange to monitor the process.
- // Return true if the LaunchInfo has taken care of monitoring the process, and false if the
- // caller might want to monitor the process themselves.
-
- bool
- MonitorProcess () const
- {
- if (GetFlags().Test(lldb::eLaunchFlagsDontMonitorProcess))
- return true;
-
- if (m_monitor_callback && ProcessIDIsValid())
- {
- Host::StartMonitoringChildProcess (m_monitor_callback,
- m_monitor_callback_baton,
- GetProcessID(),
- m_monitor_signals);
- return true;
- }
- return false;
- }
-
- lldb_utility::PseudoTerminal &
- GetPTY ()
- {
- return m_pty;
- }
-
- lldb::ListenerSP
- GetHijackListener () const
- {
- return m_hijack_listener_sp;
- }
-
- void
- SetHijackListener (const lldb::ListenerSP &listener_sp)
- {
- m_hijack_listener_sp = listener_sp;
- }
-
-
-protected:
- std::string m_working_dir;
- std::string m_plugin_name;
- std::string m_shell;
- Flags m_flags; // Bitwise OR of bits from lldb::LaunchFlags
- std::vector<FileAction> m_file_actions; // File actions for any other files
- lldb_utility::PseudoTerminal m_pty;
- uint32_t m_resume_count; // How many times do we resume after launching
- Host::MonitorChildProcessCallback m_monitor_callback;
- void *m_monitor_callback_baton;
- bool m_monitor_signals;
- lldb::ListenerSP m_hijack_listener_sp;
-};
-
-//----------------------------------------------------------------------
-// ProcessLaunchInfo
-//
-// Describes any information that is required to launch a process.
+// Describes any information that is required to attach to a process.
//----------------------------------------------------------------------
class ProcessAttachInfo : public ProcessInstanceInfo
@@ -884,7 +227,8 @@ public:
m_resume_count (0),
m_wait_for_launch (false),
m_ignore_existing (true),
- m_continue_once_attached (false)
+ m_continue_once_attached (false),
+ m_detach_on_error (true)
{
}
@@ -894,12 +238,14 @@ public:
m_resume_count (0),
m_wait_for_launch (false),
m_ignore_existing (true),
- m_continue_once_attached (false)
+ m_continue_once_attached (false),
+ m_detach_on_error(true)
{
ProcessInfo::operator= (launch_info);
SetProcessPluginName (launch_info.GetProcessPluginName());
SetResumeCount (launch_info.GetResumeCount());
SetHijackListener(launch_info.GetHijackListener());
+ m_detach_on_error = launch_info.GetDetachOnError();
}
bool
@@ -1002,7 +348,18 @@ public:
m_hijack_listener_sp = listener_sp;
}
-
+ bool
+ GetDetachOnError () const
+ {
+ return m_detach_on_error;
+ }
+
+ void
+ SetDetachOnError (bool enable)
+ {
+ m_detach_on_error = enable;
+ }
+
protected:
lldb::ListenerSP m_hijack_listener_sp;
std::string m_plugin_name;
@@ -1010,6 +367,7 @@ protected:
bool m_wait_for_launch;
bool m_ignore_existing;
bool m_continue_once_attached; // Supports the use-case scenario of immediately continuing the process once attached.
+ bool m_detach_on_error; // If we are debugging remotely, instruct the stub to detach rather than killing the target on error.
};
class ProcessLaunchCommandOptions : public Options
@@ -1034,6 +392,7 @@ public:
OptionParsingStarting ()
{
launch_info.Clear();
+ disable_aslr = eLazyBoolCalculate;
}
const OptionDefinition*
@@ -1049,6 +408,7 @@ public:
// Instance variables to hold the values for command options.
ProcessLaunchInfo launch_info;
+ lldb_private::LazyBool disable_aslr;
};
//----------------------------------------------------------------------
@@ -1321,91 +681,6 @@ inline bool operator!= (const ProcessModID &lhs, const ProcessModID &rhs)
return false;
}
-class MemoryRegionInfo
-{
-public:
- typedef Range<lldb::addr_t, lldb::addr_t> RangeType;
-
- enum OptionalBool {
- eDontKnow = -1,
- eNo = 0,
- eYes = 1
- };
-
- MemoryRegionInfo () :
- m_range (),
- m_read (eDontKnow),
- m_write (eDontKnow),
- m_execute (eDontKnow)
- {
- }
-
- ~MemoryRegionInfo ()
- {
- }
-
- RangeType &
- GetRange()
- {
- return m_range;
- }
-
- void
- Clear()
- {
- m_range.Clear();
- m_read = m_write = m_execute = eDontKnow;
- }
-
- const RangeType &
- GetRange() const
- {
- return m_range;
- }
-
- OptionalBool
- GetReadable () const
- {
- return m_read;
- }
-
- OptionalBool
- GetWritable () const
- {
- return m_write;
- }
-
- OptionalBool
- GetExecutable () const
- {
- return m_execute;
- }
-
- void
- SetReadable (OptionalBool val)
- {
- m_read = val;
- }
-
- void
- SetWritable (OptionalBool val)
- {
- m_write = val;
- }
-
- void
- SetExecutable (OptionalBool val)
- {
- m_execute = val;
- }
-
-protected:
- RangeType m_range;
- OptionalBool m_read;
- OptionalBool m_write;
- OptionalBool m_execute;
-};
-
//----------------------------------------------------------------------
/// @class Process Process.h "lldb/Target/Process.h"
/// @brief A plug-in interface definition class for debugging a process.
@@ -1418,7 +693,8 @@ class Process :
public ExecutionContextScope,
public PluginInterface
{
- friend class ClangFunction; // For WaitForStateChangeEventsPrivate
+ friend class ClangFunction; // For WaitForStateChangeEventsPrivate
+ friend class Debugger; // For PopProcessIOHandler and ProcessIOHandlerIsActive
friend class ProcessEventData;
friend class StopInfo;
friend class Target;
@@ -1619,10 +895,17 @@ public:
//------------------------------------------------------------------
/// Construct with a shared pointer to a target, and the Process listener.
+ /// Uses the Host UnixSignalsSP by default.
//------------------------------------------------------------------
Process(Target &target, Listener &listener);
//------------------------------------------------------------------
+ /// Construct with a shared pointer to a target, the Process listener,
+ /// and the appropriate UnixSignalsSP for the process.
+ //------------------------------------------------------------------
+ Process(Target &target, Listener &listener, const UnixSignalsSP &unix_signals_sp);
+
+ //------------------------------------------------------------------
/// Destructor.
///
/// The destructor is virtual since this class is designed to be
@@ -1753,10 +1036,6 @@ public:
///
/// Launch a new process by spawning a new process using the
/// target object's executable module's file as the file to launch.
- /// Arguments are given in \a argv, and the environment variables
- /// are in \a envp. Standard input and output files can be
- /// optionally re-directed to \a stdin_path, \a stdout_path, and
- /// \a stderr_path.
///
/// This function is not meant to be overridden by Process
/// subclasses. It will first call Process::WillLaunch (Module *)
@@ -1766,32 +1045,9 @@ public:
/// DoLaunch returns \b true, then Process::DidLaunch() will be
/// called.
///
- /// @param[in] argv
- /// The argument array.
- ///
- /// @param[in] envp
- /// The environment array.
- ///
- /// @param[in] launch_flags
- /// Flags to modify the launch (@see lldb::LaunchFlags)
- ///
- /// @param[in] stdin_path
- /// The path to use when re-directing the STDIN of the new
- /// process. If all stdXX_path arguments are NULL, a pseudo
- /// terminal will be used.
- ///
- /// @param[in] stdout_path
- /// The path to use when re-directing the STDOUT of the new
- /// process. If all stdXX_path arguments are NULL, a pseudo
- /// terminal will be used.
- ///
- /// @param[in] stderr_path
- /// The path to use when re-directing the STDERR of the new
- /// process. If all stdXX_path arguments are NULL, a pseudo
- /// terminal will be used.
- ///
- /// @param[in] working_directory
- /// The working directory to have the child process run in
+ /// @param[in] launch_info
+ /// Details regarding the environment, STDIN/STDOUT/STDERR
+ /// redirection, working path, etc. related to the requested launch.
///
/// @return
/// An error object. Call GetID() to get the process ID if
@@ -1824,6 +1080,22 @@ public:
GetDynamicLoader ();
//------------------------------------------------------------------
+ // Returns AUXV structure found in many ELF-based environments.
+ //
+ // The default action is to return an empty data buffer.
+ //
+ // @return
+ // A data buffer containing the contents of the AUXV data.
+ //------------------------------------------------------------------
+ virtual const lldb::DataBufferSP
+ GetAuxvData();
+
+protected:
+ virtual JITLoaderList &
+ GetJITLoaders ();
+
+public:
+ //------------------------------------------------------------------
/// Get the system runtime plug-in for this process.
///
/// @return
@@ -1930,7 +1202,7 @@ public:
//------------------------------------------------------------------
/// Register for process and thread notifications.
///
- /// Clients can register nofication callbacks by filling out a
+ /// Clients can register notification callbacks by filling out a
/// Process::Notifications structure and calling this function.
///
/// @param[in] callbacks
@@ -1946,7 +1218,7 @@ public:
//------------------------------------------------------------------
/// Unregister for process and thread notifications.
///
- /// Clients can unregister nofication callbacks by passing a copy of
+ /// Clients can unregister notification callbacks by passing a copy of
/// the original baton and callbacks in \a callbacks.
///
/// @param[in] callbacks
@@ -2056,10 +1328,18 @@ public:
Error
Signal (int signal);
- virtual UnixSignals &
+ void
+ SetUnixSignals (const UnixSignalsSP &signals_sp)
+ {
+ assert (signals_sp && "null signals_sp");
+ m_unix_signals_sp = signals_sp;
+ }
+
+ UnixSignals &
GetUnixSignals ()
{
- return m_unix_signals;
+ assert (m_unix_signals_sp && "null m_unix_signals_sp");
+ return *m_unix_signals_sp;
}
//==================================================================
@@ -2183,11 +1463,17 @@ public:
//------------------------------------------------------------------
/// Called after attaching a process.
///
+ /// @param[in] process_arch
+ /// If you can figure out the process architecture after attach, fill it in here.
+ ///
/// Allow Process plug-ins to execute some code after attaching to
/// a process.
//------------------------------------------------------------------
virtual void
- DidAttach () {}
+ DidAttach (ArchSpec &process_arch)
+ {
+ process_arch.Clear();
+ }
//------------------------------------------------------------------
@@ -2229,46 +1515,21 @@ public:
//------------------------------------------------------------------
/// Launch a new process.
///
- /// Launch a new process by spawning a new process using \a module's
- /// file as the file to launch. Arguments are given in \a argv,
- /// and the environment variables are in \a envp. Standard input
- /// and output files can be optionally re-directed to \a stdin_path,
- /// \a stdout_path, and \a stderr_path.
+ /// Launch a new process by spawning a new process using
+ /// \a exe_module's file as the file to launch. Launch details are
+ /// provided in \a launch_info.
///
- /// @param[in] module
+ /// @param[in] exe_module
/// The module from which to extract the file specification and
/// launch.
///
- /// @param[in] argv
- /// The argument array.
- ///
- /// @param[in] envp
- /// The environment array.
- ///
- /// @param[in] launch_flags
- /// Flags to modify the launch (@see lldb::LaunchFlags)
- ///
- /// @param[in] stdin_path
- /// The path to use when re-directing the STDIN of the new
- /// process. If all stdXX_path arguments are NULL, a pseudo
- /// terminal will be used.
- ///
- /// @param[in] stdout_path
- /// The path to use when re-directing the STDOUT of the new
- /// process. If all stdXX_path arguments are NULL, a pseudo
- /// terminal will be used.
- ///
- /// @param[in] stderr_path
- /// The path to use when re-directing the STDERR of the new
- /// process. If all stdXX_path arguments are NULL, a pseudo
- /// terminal will be used.
- ///
- /// @param[in] working_directory
- /// The working directory to have the child process run in
+ /// @param[in] launch_info
+ /// Details (e.g. arguments, stdio redirection, etc.) for the
+ /// requested launch.
///
/// @return
- /// A new valid process ID, or LLDB_INVALID_PROCESS_ID if
- /// launching fails.
+ /// An Error instance indicating success or failure of the
+ /// operation.
//------------------------------------------------------------------
virtual Error
DoLaunch (Module *exe_module,
@@ -2454,7 +1715,7 @@ public:
DoSignal (int signal)
{
Error error;
- error.SetErrorStringWithFormat("error: %s does not support senging signals to processes", GetPluginName().GetCString());
+ error.SetErrorStringWithFormat("error: %s does not support sending signals to processes", GetPluginName().GetCString());
return error;
}
@@ -2546,14 +1807,14 @@ public:
lldb::StateType
GetState ();
- ExecutionResults
+ lldb::ExpressionResults
RunThreadPlan (ExecutionContext &exe_ctx,
lldb::ThreadPlanSP &thread_plan_sp,
const EvaluateExpressionOptions &options,
Stream &errors);
static const char *
- ExecutionResultAsCString (ExecutionResults result);
+ ExecutionResultAsCString (lldb::ExpressionResults result);
void
GetStatus (Stream &ostrm);
@@ -2568,6 +1829,9 @@ public:
void
SendAsyncInterrupt ();
+ void
+ ModulesDidLoad (ModuleList &module_list);
+
protected:
void
@@ -2904,7 +2168,7 @@ public:
///
/// The value contained in \a scalar will be swapped to match the
/// byte order of the process that is being debugged. If \a size is
- /// less than the size of scalar, the least significate \a size bytes
+ /// less than the size of scalar, the least significant \a size bytes
/// from scalar will be written. If \a size is larger than the byte
/// size of scalar, then the extra space will be padded with zeros
/// and the scalar value will be placed in the least significant
@@ -3070,7 +2334,8 @@ public:
lldb::ModuleSP
ReadModuleFromMemory (const FileSpec& file_spec,
- lldb::addr_t header_addr);
+ lldb::addr_t header_addr,
+ size_t size_to_read = 512);
//------------------------------------------------------------------
/// Attempt to get the attributes for a region of memory in the process.
@@ -3412,6 +2677,25 @@ public:
bool wait_always = true,
Listener *hijack_listener = NULL);
+
+ //--------------------------------------------------------------------------------------
+ /// Waits for the process state to be running within a given msec timeout.
+ ///
+ /// The main purpose of this is to implement an interlock waiting for HandlePrivateEvent
+ /// to push an IOHandler.
+ ///
+ /// @param[in] timeout_msec
+ /// The maximum time length to wait for the process to transition to the
+ /// eStateRunning state, specified in milliseconds.
+ ///
+ /// @return
+ /// true if successfully signalled that process started and IOHandler pushes, false
+ /// if it timed out.
+ //--------------------------------------------------------------------------------------
+ bool
+ SyncIOHandler (uint64_t timeout_msec);
+
+
lldb::StateType
WaitForStateChangedEvents (const TimeValue *timeout,
lldb::EventSP &event_sp,
@@ -3582,12 +2866,6 @@ public:
void
SetSTDIOFileDescriptor (int file_descriptor);
- void
- WatchForSTDIN (IOHandler &io_handler);
-
- void
- CancelWatchForSTDIN (bool exited);
-
//------------------------------------------------------------------
// Add a permanent region of memory that should never be read or
// written to. This can be used to ensure that memory reads or writes
@@ -3633,8 +2911,17 @@ public:
else
return m_public_run_lock;
}
-
+
+public:
+ virtual Error
+ SendEventData(const char *data)
+ {
+ Error return_error ("Sending an event is not supported for this process.");
+ return return_error;
+ }
+
protected:
+
//------------------------------------------------------------------
// NextEventAction provides a way to register an action on the next
// event that is delivered to this process. There is currently only
@@ -3690,13 +2977,9 @@ protected:
class AttachCompletionHandler : public NextEventAction
{
public:
- AttachCompletionHandler (Process *process, uint32_t exec_count) :
- NextEventAction (process),
- m_exec_count (exec_count)
- {
- }
+ AttachCompletionHandler (Process *process, uint32_t exec_count);
- virtual
+ virtual
~AttachCompletionHandler()
{
}
@@ -3753,7 +3036,7 @@ protected:
Broadcaster m_private_state_control_broadcaster; // This is the control broadcaster, used to pause, resume & stop the private state thread.
Listener m_private_state_listener; // This is the listener for the private state thread.
Predicate<bool> m_private_state_control_wait; /// This Predicate is used to signal that a control operation is complete.
- lldb::thread_t m_private_state_thread; // Thread ID for the thread that watches interal state events
+ lldb::thread_t m_private_state_thread; // Thread ID for the thread that watches internal state events
ProcessModID m_mod_id; ///< Tracks the state of the process over stops and other alterations.
uint32_t m_process_unique_id; ///< Each lldb_private::Process class that is created gets a unique integer ID that increments with each new instance
uint32_t m_thread_index_id; ///< Each thread is created with a 1 based index that won't get re-used.
@@ -3773,10 +3056,11 @@ protected:
Listener &m_listener;
BreakpointSiteList m_breakpoint_site_list; ///< This is the list of breakpoint locations we intend to insert in the target.
std::unique_ptr<DynamicLoader> m_dyld_ap;
+ std::unique_ptr<JITLoaderList> m_jit_loaders_ap;
std::unique_ptr<DynamicCheckerFunctions> m_dynamic_checkers_ap; ///< The functions used by the expression parser to validate data that expressions use.
std::unique_ptr<OperatingSystem> m_os_ap;
std::unique_ptr<SystemRuntime> m_system_runtime_ap;
- UnixSignals m_unix_signals; /// This is the current signal set for this process.
+ UnixSignalsSP m_unix_signals_sp; /// This is the current signal set for this process.
lldb::ABISP m_abi_sp;
lldb::IOHandlerSP m_process_input_reader;
Communication m_stdio_communication;
@@ -3785,6 +3069,7 @@ protected:
std::string m_stderr_data;
Mutex m_profile_data_comm_mutex;
std::vector<std::string> m_profile_data;
+ Predicate<bool> m_iohandler_sync;
MemoryCache m_memory_cache;
AllocatedMemoryCache m_allocated_memory_cache;
bool m_should_detach; /// Should we detach if the process object goes away with an explicit call to Kill or Detach?
@@ -3874,15 +3159,15 @@ protected:
static void
STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len);
- void
+ bool
PushProcessIOHandler ();
- void
+ bool
PopProcessIOHandler ();
- void
- ResetProcessIOHandler ();
-
+ bool
+ ProcessIOHandlerIsActive ();
+
Error
HaltForDestroyOrDetach(lldb::EventSP &exit_event_sp);
diff --git a/include/lldb/Target/ProcessInfo.h b/include/lldb/Target/ProcessInfo.h
new file mode 100644
index 000000000000..0570cfc98651
--- /dev/null
+++ b/include/lldb/Target/ProcessInfo.h
@@ -0,0 +1,188 @@
+//===-- ProcessInfo.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_ProcessInfo_h_
+#define liblldb_ProcessInfo_h_
+
+// LLDB headers
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Interpreter/Args.h"
+
+namespace lldb_private
+{
+ //----------------------------------------------------------------------
+ // ProcessInfo
+ //
+ // A base class for information for a process. This can be used to fill
+ // out information for a process prior to launching it, or it can be
+ // used for an instance of a process and can be filled in with the
+ // existing values for that process.
+ //----------------------------------------------------------------------
+ class ProcessInfo
+ {
+ public:
+ ProcessInfo ();
+
+ ProcessInfo (const char *name,
+ const ArchSpec &arch,
+ lldb::pid_t pid);
+
+ void
+ Clear ();
+
+ const char *
+ GetName() const;
+
+ size_t
+ GetNameLength() const;
+
+ FileSpec &
+ GetExecutableFile ()
+ {
+ return m_executable;
+ }
+
+ void
+ SetExecutableFile (const FileSpec &exe_file, bool add_exe_file_as_first_arg);
+
+ const FileSpec &
+ GetExecutableFile () const
+ {
+ return m_executable;
+ }
+
+ uint32_t
+ GetUserID() const
+ {
+ return m_uid;
+ }
+
+ uint32_t
+ GetGroupID() const
+ {
+ return m_gid;
+ }
+
+ bool
+ UserIDIsValid () const
+ {
+ return m_uid != UINT32_MAX;
+ }
+
+ bool
+ GroupIDIsValid () const
+ {
+ return m_gid != UINT32_MAX;
+ }
+
+ void
+ SetUserID (uint32_t uid)
+ {
+ m_uid = uid;
+ }
+
+ void
+ SetGroupID (uint32_t gid)
+ {
+ m_gid = gid;
+ }
+
+ ArchSpec &
+ GetArchitecture ()
+ {
+ return m_arch;
+ }
+
+ const ArchSpec &
+ GetArchitecture () const
+ {
+ return m_arch;
+ }
+
+ void
+ SetArchitecture (ArchSpec arch)
+ {
+ m_arch = arch;
+ }
+
+ lldb::pid_t
+ GetProcessID () const
+ {
+ return m_pid;
+ }
+
+ void
+ SetProcessID (lldb::pid_t pid)
+ {
+ m_pid = pid;
+ }
+
+ bool
+ ProcessIDIsValid() const
+ {
+ return m_pid != LLDB_INVALID_PROCESS_ID;
+ }
+
+ void
+ Dump (Stream &s, Platform *platform) const;
+
+ Args &
+ GetArguments ()
+ {
+ return m_arguments;
+ }
+
+ const Args &
+ GetArguments () const
+ {
+ return m_arguments;
+ }
+
+ const char *
+ GetArg0 () const;
+
+ void
+ SetArg0 (const char *arg);
+
+ void
+ SetArguments (const Args& args, bool first_arg_is_executable);
+
+ void
+ SetArguments (char const **argv, bool first_arg_is_executable);
+
+ Args &
+ GetEnvironmentEntries ()
+ {
+ return m_environment;
+ }
+
+ const Args &
+ GetEnvironmentEntries () const
+ {
+ return m_environment;
+ }
+
+ protected:
+ FileSpec m_executable;
+ std::string m_arg0; // argv[0] if supported. If empty, then use m_executable.
+ // Not all process plug-ins support specifying an argv[0]
+ // that differs from the resolved platform executable
+ // (which is in m_executable)
+ Args m_arguments; // All program arguments except argv[0]
+ Args m_environment;
+ uint32_t m_uid;
+ uint32_t m_gid;
+ ArchSpec m_arch;
+ lldb::pid_t m_pid;
+ };
+}
+
+#endif // #ifndef liblldb_ProcessInfo_h_
+
diff --git a/include/lldb/Target/ProcessLaunchInfo.h b/include/lldb/Target/ProcessLaunchInfo.h
new file mode 100644
index 000000000000..77d829a7e476
--- /dev/null
+++ b/include/lldb/Target/ProcessLaunchInfo.h
@@ -0,0 +1,225 @@
+//===-- ProcessLaunchInfo.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_ProcessLaunch_Info_h
+#define liblldb_ProcessLaunch_Info_h
+
+// C++ Headers
+#include <string>
+
+// LLDB Headers
+#include "lldb/Core/Flags.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/FileAction.h"
+#include "lldb/Target/ProcessInfo.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+namespace lldb_private
+{
+
+ //----------------------------------------------------------------------
+ // ProcessLaunchInfo
+ //
+ // Describes any information that is required to launch a process.
+ //----------------------------------------------------------------------
+
+ class ProcessLaunchInfo : public ProcessInfo
+ {
+ public:
+
+ ProcessLaunchInfo ();
+
+ ProcessLaunchInfo (const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_directory,
+ uint32_t launch_flags);
+
+ void
+ AppendFileAction (const FileAction &info)
+ {
+ m_file_actions.push_back(info);
+ }
+
+ bool
+ AppendCloseFileAction (int fd);
+
+ bool
+ AppendDuplicateFileAction (int fd, int dup_fd);
+
+ bool
+ AppendOpenFileAction (int fd, const char *path, bool read, bool write);
+
+ bool
+ AppendSuppressFileAction (int fd, bool read, bool write);
+
+ void
+ FinalizeFileActions (Target *target,
+ bool default_to_use_pty);
+
+ size_t
+ GetNumFileActions () const
+ {
+ return m_file_actions.size();
+ }
+
+ const FileAction *
+ GetFileActionAtIndex (size_t idx) const;
+
+ const FileAction *
+ GetFileActionForFD (int fd) const;
+
+ Flags &
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const Flags &
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ const char *
+ GetWorkingDirectory () const;
+
+ void
+ SetWorkingDirectory (const char *working_dir);
+
+ void
+ SwapWorkingDirectory (std::string &working_dir)
+ {
+ m_working_dir.swap (working_dir);
+ }
+
+ const char *
+ GetProcessPluginName () const;
+
+ void
+ SetProcessPluginName (const char *plugin);
+
+ const char *
+ GetShell () const;
+
+ void
+ SetShell (const char * path);
+
+ uint32_t
+ GetResumeCount () const
+ {
+ return m_resume_count;
+ }
+
+ void
+ SetResumeCount (uint32_t c)
+ {
+ m_resume_count = c;
+ }
+
+ bool
+ GetLaunchInSeparateProcessGroup ()
+ {
+ return m_flags.Test(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
+ }
+
+ void
+ SetLaunchInSeparateProcessGroup (bool separate);
+
+ void
+ Clear ();
+
+ bool
+ ConvertArgumentsForLaunchingInShell (Error &error,
+ bool localhost,
+ bool will_debug,
+ bool first_arg_is_full_shell_command,
+ int32_t num_resumes);
+
+ void
+ SetMonitorProcessCallback (Host::MonitorChildProcessCallback callback,
+ void *baton,
+ bool monitor_signals);
+
+ Host::MonitorChildProcessCallback
+ GetMonitorProcessCallback ()
+ {
+ return m_monitor_callback;
+ }
+
+ const void*
+ GetMonitorProcessBaton () const
+ {
+ return m_monitor_callback_baton;
+ }
+
+ // If the LaunchInfo has a monitor callback, then arrange to monitor the process.
+ // Return true if the LaunchInfo has taken care of monitoring the process, and false if the
+ // caller might want to monitor the process themselves.
+
+ bool
+ MonitorProcess () const;
+
+ lldb_utility::PseudoTerminal &
+ GetPTY ()
+ {
+ return m_pty;
+ }
+
+ lldb::ListenerSP
+ GetHijackListener () const
+ {
+ return m_hijack_listener_sp;
+ }
+
+ void
+ SetHijackListener (const lldb::ListenerSP &listener_sp)
+ {
+ m_hijack_listener_sp = listener_sp;
+ }
+
+
+ void
+ SetLaunchEventData (const char *data)
+ {
+ m_event_data.assign (data);
+ }
+
+ const char *
+ GetLaunchEventData () const
+ {
+ return m_event_data.c_str();
+ }
+
+ void
+ SetDetachOnError (bool enable);
+
+ bool
+ GetDetachOnError () const
+ {
+ return m_flags.Test(lldb::eLaunchFlagDetachOnError);
+ }
+
+ protected:
+ std::string m_working_dir;
+ std::string m_plugin_name;
+ std::string m_shell;
+ Flags m_flags; // Bitwise OR of bits from lldb::LaunchFlags
+ std::vector<FileAction> m_file_actions; // File actions for any other files
+ lldb_utility::PseudoTerminal m_pty;
+ uint32_t m_resume_count; // How many times do we resume after launching
+ Host::MonitorChildProcessCallback m_monitor_callback;
+ void *m_monitor_callback_baton;
+ bool m_monitor_signals;
+ std::string m_event_data; // A string passed to the plugin launch, having no meaning to the upper levels of lldb.
+ lldb::ListenerSP m_hijack_listener_sp;
+ };
+}
+
+#endif // liblldb_ProcessLaunch_Info_h
diff --git a/include/lldb/Target/Queue.h b/include/lldb/Target/Queue.h
index 32ee24aebc11..514481fe8c9d 100644
--- a/include/lldb/Target/Queue.h
+++ b/include/lldb/Target/Queue.h
@@ -168,6 +168,18 @@ public:
m_pending_items.push_back (item);
}
+ //------------------------------------------------------------------
+ /// Return the kind (serial, concurrent) of this queue
+ ///
+ /// @return
+ // Whether this is a serial or a concurrent queue
+ //------------------------------------------------------------------
+ lldb::QueueKind
+ GetKind ();
+
+ void
+ SetKind (lldb::QueueKind kind);
+
private:
//------------------------------------------------------------------
// For Queue only
@@ -180,6 +192,7 @@ private:
uint32_t m_pending_work_items_count;
std::vector<lldb::QueueItemSP> m_pending_items;
lldb::addr_t m_dispatch_queue_t_addr; // address of libdispatch dispatch_queue_t for this Queue
+ lldb::QueueKind m_kind;
DISALLOW_COPY_AND_ASSIGN (Queue);
};
diff --git a/include/lldb/Target/QueueItem.h b/include/lldb/Target/QueueItem.h
index 76270da3bee6..c69c825a7976 100644
--- a/include/lldb/Target/QueueItem.h
+++ b/include/lldb/Target/QueueItem.h
@@ -14,6 +14,7 @@
#include "lldb/lldb-private.h"
#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/ConstString.h"
@@ -37,7 +38,7 @@ class QueueItem :
{
public:
- QueueItem (lldb::QueueSP queue_sp);
+ QueueItem (lldb::QueueSP queue_sp, lldb::ProcessSP process_sp, lldb::addr_t item_ref, lldb_private::Address address);
~QueueItem ();
@@ -49,7 +50,7 @@ public:
/// represents. eQueueItemKindUnknown may be returned.
//------------------------------------------------------------------
lldb::QueueItemKind
- GetKind () const;
+ GetKind ();
//------------------------------------------------------------------
/// Set the type of work item this is
@@ -124,10 +125,7 @@ public:
}
lldb::addr_t
- GetItemThatEnqueuedThis ()
- {
- return m_item_that_enqueued_this_ref;
- }
+ GetItemThatEnqueuedThis ();
void
SetEnqueueingThreadID (lldb::tid_t tid)
@@ -136,10 +134,7 @@ public:
}
lldb::tid_t
- GetEnqueueingThreadID ()
- {
- return m_enqueueing_thread_id;
- }
+ GetEnqueueingThreadID ();
void
SetEnqueueingQueueID (lldb::queue_id_t qid)
@@ -148,10 +143,7 @@ public:
}
lldb::queue_id_t
- GetEnqueueingQueueID ()
- {
- return m_enqueueing_queue_id;
- }
+ GetEnqueueingQueueID ();
void
SetTargetQueueID (lldb::queue_id_t qid)
@@ -166,10 +158,7 @@ public:
}
uint32_t
- GetStopID ()
- {
- return m_stop_id;
- }
+ GetStopID ();
void
SetEnqueueingBacktrace (std::vector<lldb::addr_t> backtrace)
@@ -178,10 +167,7 @@ public:
}
std::vector<lldb::addr_t> &
- GetEnqueueingBacktrace ()
- {
- return m_backtrace;
- }
+ GetEnqueueingBacktrace ();
void
SetThreadLabel (std::string thread_name)
@@ -190,10 +176,7 @@ public:
}
std::string
- GetThreadLabel ()
- {
- return m_thread_label;
- }
+ GetThreadLabel ();
void
SetQueueLabel (std::string queue_name)
@@ -202,10 +185,7 @@ public:
}
std::string
- GetQueueLabel ()
- {
- return m_queue_label;
- }
+ GetQueueLabel ();
void
SetTargetQueueLabel (std::string queue_name)
@@ -213,11 +193,22 @@ public:
m_target_queue_label = queue_name;
}
+ lldb::ProcessSP
+ GetProcessSP ();
+
protected:
+ void
+ FetchEntireItem ();
+
+
lldb::QueueWP m_queue_wp;
- lldb::QueueItemKind m_kind;
+ lldb::ProcessWP m_process_wp;
+
+ lldb::addr_t m_item_ref; // the token we can be used to fetch more information about this queue item
lldb_private::Address m_address;
+ bool m_have_fetched_entire_item;
+ lldb::QueueItemKind m_kind;
lldb::addr_t m_item_that_enqueued_this_ref; // a handle that we can pass into libBacktraceRecording
// to get the QueueItem that enqueued this item
lldb::tid_t m_enqueueing_thread_id; // thread that enqueued this item
diff --git a/include/lldb/Target/QueueList.h b/include/lldb/Target/QueueList.h
index 964c1099233e..12a0ea52d7f4 100644
--- a/include/lldb/Target/QueueList.h
+++ b/include/lldb/Target/QueueList.h
@@ -98,7 +98,7 @@ public:
///
/// @return
/// A QueueSP to the queue requested, if it is present in the QueueList.
- /// An empty QueueSP willbe returned if this queue was not found.
+ /// An empty QueueSP will be returned if this queue was not found.
//------------------------------------------------------------------
lldb::QueueSP
FindQueueByID (lldb::queue_id_t qid);
@@ -114,7 +114,7 @@ public:
///
/// @return
/// A QueueSP to the queue requested, if it is present in the QueueList.
- /// An empty QueueSP willbe returned if this queue was not found.
+ /// An empty QueueSP will be returned if this queue was not found.
//------------------------------------------------------------------
lldb::QueueSP
FindQueueByIndexID (uint32_t index_id);
diff --git a/include/lldb/Target/RegisterContext.h b/include/lldb/Target/RegisterContext.h
index 421acc03cb22..9108d4575259 100644
--- a/include/lldb/Target/RegisterContext.h
+++ b/include/lldb/Target/RegisterContext.h
@@ -86,9 +86,44 @@ public:
bool
CopyFromRegisterContext (lldb::RegisterContextSP context);
-
+
+ //------------------------------------------------------------------
+ /// Convert from a given register numbering scheme to the lldb register
+ /// numbering scheme
+ ///
+ /// There may be multiple ways to enumerate the registers for a given
+ /// architecture. ABI references will specify one to be used with
+ /// DWARF, the register numberings from stabs (aka "gcc"), there may
+ /// be a variation used for eh_frame unwind instructions (e.g. on Darwin),
+ /// and so on. Register 5 by itself is meaningless - RegisterKind
+ /// enumeration tells you what context that number should be translated as.
+ ///
+ /// Inside lldb, register numbers are in the eRegisterKindLLDB scheme;
+ /// arguments which take a register number should take one in that
+ /// scheme.
+ ///
+ /// eRegisterKindGeneric is a special numbering scheme which gives us
+ /// constant values for the pc, frame register, stack register, etc., for
+ /// use within lldb. They may not be defined for all architectures but
+ /// it allows generic code to translate these common registers into the
+ /// lldb numbering scheme.
+ ///
+ /// This method translates a given register kind + register number into
+ /// the eRegisterKindLLDB register numbering.
+ ///
+ /// @param [in] kind
+ /// The register numbering scheme (RegisterKind) that the following
+ /// register number is in.
+ ///
+ /// @param [in] num
+ /// A register number in the 'kind' register numbering scheme.
+ ///
+ /// @return
+ /// The equivalent register number in the eRegisterKindLLDB
+ /// numbering scheme, if possible, else LLDB_INVALID_REGNUM.
+ //------------------------------------------------------------------
virtual uint32_t
- ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) = 0;
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) = 0;
//------------------------------------------------------------------
// Subclasses can override these functions if desired
@@ -136,7 +171,7 @@ public:
GetRegisterInfoByName (const char *reg_name, uint32_t start_idx = 0);
const RegisterInfo *
- GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num);
+ GetRegisterInfo (lldb::RegisterKind reg_kind, uint32_t reg_num);
uint64_t
GetPC (uint64_t fail_value = LLDB_INVALID_ADDRESS);
@@ -179,7 +214,7 @@ public:
bool
WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval);
bool
- ConvertBetweenRegisterKinds (int source_rk, uint32_t source_regnum, int target_rk, uint32_t& target_regnum);
+ ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint32_t source_regnum, lldb::RegisterKind target_rk, uint32_t& target_regnum);
//------------------------------------------------------------------
// lldb::ExecutionContextScope pure virtual functions
diff --git a/include/lldb/Target/StackFrame.h b/include/lldb/Target/StackFrame.h
index e7b57cd26ac9..1274dcc64bd3 100644
--- a/include/lldb/Target/StackFrame.h
+++ b/include/lldb/Target/StackFrame.h
@@ -177,7 +177,7 @@ public:
///
/// The StackFrame maintains this SymbolContext and adds additional information
/// to it on an as-needed basis. This helps to avoid different functions
- /// looking up symbolic information for a given pc value multple times.
+ /// looking up symbolic information for a given pc value multiple times.
///
/// @params [in] resolve_scope
/// Flags from the SymbolContextItem enumerated type which specify what
@@ -261,7 +261,7 @@ public:
///
/// @param[in] get_file_globals
/// Whether to also retrieve compilation-unit scoped variables
- /// that are visisble to the entire compilation unit (e.g. file
+ /// that are visible to the entire compilation unit (e.g. file
/// static in C, globals that are homed in this CU).
///
/// @return
@@ -279,7 +279,7 @@ public:
///
/// @param[in] get_file_globals
/// Whether to also retrieve compilation-unit scoped variables
- /// that are visisble to the entire compilation unit (e.g. file
+ /// that are visible to the entire compilation unit (e.g. file
/// static in C, globals that are homed in this CU).
///
/// @return
diff --git a/include/lldb/Target/StopInfo.h b/include/lldb/Target/StopInfo.h
index 3435d392e2b9..8de40e852f4c 100644
--- a/include/lldb/Target/StopInfo.h
+++ b/include/lldb/Target/StopInfo.h
@@ -157,7 +157,9 @@ public:
CreateStopReasonToTrace (Thread &thread);
static lldb::StopInfoSP
- CreateStopReasonWithPlan (lldb::ThreadPlanSP &plan, lldb::ValueObjectSP return_valobj_sp);
+ CreateStopReasonWithPlan (lldb::ThreadPlanSP &plan,
+ lldb::ValueObjectSP return_valobj_sp,
+ lldb::ClangExpressionVariableSP expression_variable_sp);
static lldb::StopInfoSP
CreateStopReasonWithException (Thread &thread, const char *description);
@@ -168,6 +170,9 @@ public:
static lldb::ValueObjectSP
GetReturnValueObject (lldb::StopInfoSP &stop_info_sp);
+ static lldb::ClangExpressionVariableSP
+ GetExpressionVariable (lldb::StopInfoSP &stop_info_sp);
+
protected:
// Perform any action that is associated with this stop. This is done as the
// Event is removed from the event queue. ProcessEventData::DoOnRemoval does the job.
diff --git a/include/lldb/Target/SystemRuntime.h b/include/lldb/Target/SystemRuntime.h
index 363ce122c4f3..18f38f79bdbd 100644
--- a/include/lldb/Target/SystemRuntime.h
+++ b/include/lldb/Target/SystemRuntime.h
@@ -20,6 +20,7 @@
#include "lldb/Core/ConstString.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Target/QueueList.h"
#include "lldb/Target/QueueItem.h"
#include "lldb/lldb-private.h"
@@ -222,7 +223,7 @@ public:
/// get the queue name and return it.
///
/// @param [in] dispatch_qaddr
- /// The address of the dispatch_queue_t structure for this thread.
+ /// The address of the dispatch_qaddr pointer for this thread.
///
/// @return
/// The string of this queue's name. An empty string is returned if the
@@ -244,7 +245,7 @@ public:
/// get the queue ID and return it.
///
/// @param [in] dispatch_qaddr
- /// The address of the dispatch_queue_t structure for this thread.
+ /// The address of the dispatch_qaddr pointer for this thread.
///
/// @return
/// The queue ID, or if it could not be retrieved, LLDB_INVALID_QUEUE_ID.
@@ -256,6 +257,26 @@ public:
}
//------------------------------------------------------------------
+ /// Get the libdispatch_queue_t address for the queue given the thread's dispatch_qaddr.
+ ///
+ /// On systems using libdispatch queues, a thread may be associated with a queue.
+ /// There will be a call to get the thread's dispatch_qaddr.
+ /// Given the thread's dispatch_qaddr, find the libdispatch_queue_t address and
+ /// return it.
+ ///
+ /// @param [in] dispatch_qaddr
+ /// The address of the dispatch_qaddr pointer for this thread.
+ ///
+ /// @return
+ /// The libdispatch_queue_t address, or LLDB_INVALID_ADDRESS if unavailable/not found.
+ //------------------------------------------------------------------
+ virtual lldb::addr_t
+ GetLibdispatchQueueAddressFromThreadQAddress (lldb::addr_t dispatch_qaddr)
+ {
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ //------------------------------------------------------------------
/// Get the pending work items for a libdispatch Queue
///
/// If this system/process is using libdispatch and the runtime can do so,
@@ -270,6 +291,60 @@ public:
{
}
+ //------------------------------------------------------------------
+ /// Complete the fields in a QueueItem
+ ///
+ /// PopulatePendingItemsForQueue() may not fill in all of the QueueItem
+ /// details; when the remaining fields are needed, they will be
+ /// fetched by call this method.
+ ///
+ /// @param [in] queue_item
+ /// The QueueItem that we will be completing.
+ ///
+ /// @param [in] item_ref
+ /// The item_ref token that is needed to retrieve the rest of the
+ /// information about the QueueItem.
+ //------------------------------------------------------------------
+ virtual void
+ CompleteQueueItem (lldb_private::QueueItem *queue_item, lldb::addr_t item_ref)
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Add key-value pairs to the StructuredData dictionary object with
+ /// information debugserver may need when constructing the jThreadExtendedInfo
+ /// packet.
+ ///
+ /// @param [out] dict
+ /// Dictionary to which key-value pairs should be added; they will
+ /// be sent to the remote gdb server stub as arguments in the
+ /// jThreadExtendedInfo request.
+ //------------------------------------------------------------------
+ virtual void
+ AddThreadExtendedInfoPacketHints (lldb_private::StructuredData::ObjectSP dict)
+ {
+ }
+
+ /// Determine whether it is safe to run an expression on a given thread
+ ///
+ /// If a system must not run functions on a thread in some particular state,
+ /// this method gives a way for it to flag that the expression should not be
+ /// run.
+ ///
+ /// @param [in] thread_sp
+ /// The thread we want to run the expression on.
+ ///
+ /// @return
+ /// True will be returned if there are no known problems with running an
+ /// expression on this thread. False means that the inferior function
+ /// call should not be made on this thread.
+ //------------------------------------------------------------------
+ virtual bool
+ SafeToCallFunctionsOnThisThread (lldb::ThreadSP thread_sp)
+ {
+ return true;
+ }
+
protected:
//------------------------------------------------------------------
// Member variables.
diff --git a/include/lldb/Target/Target.h b/include/lldb/Target/Target.h
index e65a511ab77a..64f3edf0fc4f 100644
--- a/include/lldb/Target/Target.h
+++ b/include/lldb/Target/Target.h
@@ -82,6 +82,12 @@ public:
SetDisableASLR (bool b);
bool
+ GetDetachOnError () const;
+
+ void
+ SetDetachOnError (bool b);
+
+ bool
GetDisableSTDIO () const;
void
@@ -201,9 +207,15 @@ public:
m_stop_others(true),
m_debug(false),
m_trap_exceptions(true),
+ m_generate_debug_info(false),
+ m_result_is_internal(false),
m_use_dynamic(lldb::eNoDynamicValues),
- m_timeout_usec(default_timeout)
- {}
+ m_timeout_usec(default_timeout),
+ m_one_thread_timeout_usec(0),
+ m_cancel_callback (nullptr),
+ m_cancel_callback_baton (nullptr)
+ {
+ }
ExecutionPolicy
GetExecutionPolicy () const
@@ -301,6 +313,18 @@ public:
m_timeout_usec = timeout;
}
+ uint32_t
+ GetOneThreadTimeoutUsec () const
+ {
+ return m_one_thread_timeout_usec;
+ }
+
+ void
+ SetOneThreadTimeoutUsec (uint32_t timeout = 0)
+ {
+ m_one_thread_timeout_usec = timeout;
+ }
+
bool
GetTryAllThreads () const
{
@@ -335,6 +359,20 @@ public:
SetDebug(bool b)
{
m_debug = b;
+ if (m_debug)
+ m_generate_debug_info = true;
+ }
+
+ bool
+ GetGenerateDebugInfo() const
+ {
+ return m_generate_debug_info;
+ }
+
+ void
+ SetGenerateDebugInfo(bool b)
+ {
+ m_generate_debug_info = b;
}
bool
@@ -348,6 +386,34 @@ public:
{
m_trap_exceptions = b;
}
+
+ void
+ SetCancelCallback (lldb::ExpressionCancelCallback callback, void *baton)
+ {
+ m_cancel_callback_baton = baton;
+ m_cancel_callback = callback;
+ }
+
+ bool
+ InvokeCancelCallback (lldb::ExpressionEvaluationPhase phase) const
+ {
+ if (m_cancel_callback == nullptr)
+ return false;
+ else
+ return m_cancel_callback (phase, m_cancel_callback_baton);
+ }
+
+ void
+ SetResultIsInternal (bool b)
+ {
+ m_result_is_internal = b;
+ }
+
+ bool
+ GetResultIsInternal () const
+ {
+ return m_result_is_internal;
+ }
private:
ExecutionPolicy m_execution_policy;
@@ -360,8 +426,13 @@ private:
bool m_stop_others;
bool m_debug;
bool m_trap_exceptions;
+ bool m_generate_debug_info;
+ bool m_result_is_internal;
lldb::DynamicValueType m_use_dynamic;
uint32_t m_timeout_usec;
+ uint32_t m_one_thread_timeout_usec;
+ lldb::ExpressionCancelCallback m_cancel_callback;
+ void *m_cancel_callback_baton;
};
//----------------------------------------------------------------------
@@ -513,7 +584,7 @@ public:
/// in a target.
///
/// @param[in] s
- /// The stream to which to dump the object descripton.
+ /// The stream to which to dump the object description.
//------------------------------------------------------------------
void
Dump (Stream *s, lldb::DescriptionLevel description_level);
@@ -1086,7 +1157,7 @@ public:
// we provide a way for expressions to be evaluated from the Target itself.
// If an expression is going to be run, then it should have a frame filled
// in in th execution context.
- ExecutionResults
+ lldb::ExpressionResults
EvaluateExpression (const char *expression,
StackFrame *frame,
lldb::ValueObjectSP &result_valobj_sp,
diff --git a/include/lldb/Target/TargetList.h b/include/lldb/Target/TargetList.h
index 41404e11c7fa..6abf13e8704c 100644
--- a/include/lldb/Target/TargetList.h
+++ b/include/lldb/Target/TargetList.h
@@ -121,7 +121,7 @@ public:
//------------------------------------------------------------------
/// Delete a Target object from the list.
///
- /// When clients are done with the Target objets, this function
+ /// When clients are done with the Target objects, this function
/// should be called to release the memory associated with a target
/// object.
///
diff --git a/include/lldb/Target/Thread.h b/include/lldb/Target/Thread.h
index 20687e977bff..cba09e164105 100644
--- a/include/lldb/Target/Thread.h
+++ b/include/lldb/Target/Thread.h
@@ -14,6 +14,7 @@
#include "lldb/Host/Mutex.h"
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Event.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Core/UserID.h"
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Target/ExecutionContextScope.h"
@@ -49,6 +50,12 @@ public:
bool
GetTraceEnabledState() const;
+
+ bool
+ GetStepInAvoidsNoDebug () const;
+
+ bool
+ GetStepOutAvoidsNoDebug () const;
};
typedef std::shared_ptr<ThreadProperties> ThreadPropertiesSP;
@@ -153,7 +160,25 @@ public:
static const ThreadPropertiesSP &
GetGlobalProperties();
- Thread (Process &process, lldb::tid_t tid);
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param [in] process
+ ///
+ /// @param [in] tid
+ ///
+ /// @param [in] use_invalid_index_id
+ /// Optional parameter, defaults to false. The only subclass that
+ /// is likely to set use_invalid_index_id == true is the HistoryThread
+ /// class. In that case, the Thread we are constructing represents
+ /// a thread from earlier in the program execution. We may have the
+ /// tid of the original thread that they represent but we don't want
+ /// to reuse the IndexID of that thread, or create a new one. If a
+ /// client wants to know the original thread's IndexID, they should use
+ /// Thread::GetExtendedBacktraceOriginatingIndexID().
+ //------------------------------------------------------------------
+ Thread (Process &process, lldb::tid_t tid, bool use_invalid_index_id = false);
+
virtual ~Thread();
lldb::ProcessSP
@@ -185,10 +210,22 @@ public:
{
return m_resume_state;
}
-
+
+ // This sets the "external resume state" of the thread. If the thread is suspended here, it should never
+ // get scheduled. Note that just because a thread is marked as "running" does not mean we will let it run in
+ // a given bit of process control. For instance "step" tries to stay on the selected thread it was issued on,
+ // which may involve suspending other threads temporarily. This temporary suspension is NOT reflected in the
+ // state set here and reported in GetResumeState.
+ //
+ // If you are just preparing all threads to run, you should not override the threads that are
+ // marked as suspended by the debugger. In that case, pass override_suspend = false. If you want
+ // to force the thread to run (e.g. the "thread continue" command, or are resetting the state
+ // (e.g. in SBThread::Resume()), then pass true to override_suspend.
void
- SetResumeState (lldb::StateType state)
+ SetResumeState (lldb::StateType state, bool override_suspend = false)
{
+ if (m_resume_state == lldb::eStateSuspended && !override_suspend)
+ return;
m_resume_state = state;
}
@@ -270,6 +307,28 @@ public:
return NULL;
}
+ //------------------------------------------------------------------
+ /// Retrieve a dictionary of information about this thread
+ ///
+ /// On Mac OS X systems there may be voucher information.
+ /// The top level dictionary returned will have an "activity" key and the
+ /// value of the activity is a dictionary. Keys in that dictionary will
+ /// be "name" and "id", among others.
+ /// There may also be "trace_messages" (an array) with each entry in that array
+ /// being a dictionary (keys include "message" with the text of the trace
+ /// message).
+ //------------------------------------------------------------------
+ StructuredData::ObjectSP
+ GetExtendedInfo ()
+ {
+ if (m_extended_info_fetched == false)
+ {
+ m_extended_info = FetchThreadExtendedInfo ();
+ m_extended_info_fetched = true;
+ }
+ return m_extended_info;
+ }
+
virtual const char *
GetName ()
{
@@ -281,6 +340,21 @@ public:
{
}
+ //------------------------------------------------------------------
+ /// Retrieve the Queue ID for the queue currently using this Thread
+ ///
+ /// If this Thread is doing work on behalf of a libdispatch/GCD queue,
+ /// retrieve the QueueID.
+ ///
+ /// This is a unique identifier for the libdispatch/GCD queue in a
+ /// process. Often starting at 1 for the initial system-created
+ /// queues and incrementing, a QueueID will not be reused for a
+ /// different queue during the lifetime of a proces.
+ ///
+ /// @return
+ /// A QueueID if the Thread subclass implements this, else
+ /// LLDB_INVALID_QUEUE_ID.
+ //------------------------------------------------------------------
virtual lldb::queue_id_t
GetQueueID ()
{
@@ -292,6 +366,16 @@ public:
{
}
+ //------------------------------------------------------------------
+ /// Retrieve the Queue name for the queue currently using this Thread
+ ///
+ /// If this Thread is doing work on behalf of a libdispatch/GCD queue,
+ /// retrieve the Queue name.
+ ///
+ /// @return
+ /// The Queue name, if the Thread subclass implements this, else
+ /// NULL.
+ //------------------------------------------------------------------
virtual const char *
GetQueueName ()
{
@@ -303,6 +387,44 @@ public:
{
}
+ //------------------------------------------------------------------
+ /// Retrieve the Queue for this thread, if any.
+ ///
+ /// @return
+ /// A QueueSP for the queue that is currently associated with this
+ /// thread.
+ /// An empty shared pointer indicates that this thread is not
+ /// associated with a queue, or libdispatch queues are not
+ /// supported on this target.
+ //------------------------------------------------------------------
+ virtual lldb::QueueSP
+ GetQueue ()
+ {
+ return lldb::QueueSP();
+ }
+
+ //------------------------------------------------------------------
+ /// Retrieve the address of the libdispatch_queue_t struct for queue
+ /// currently using this Thread
+ ///
+ /// If this Thread is doing work on behalf of a libdispatch/GCD queue,
+ /// retrieve the address of the libdispatch_queue_t structure describing
+ /// the queue.
+ ///
+ /// This address may be reused for different queues later in the Process
+ /// lifetime and should not be used to identify a queue uniquely. Use
+ /// the GetQueueID() call for that.
+ ///
+ /// @return
+ /// The Queue's libdispatch_queue_t address if the Thread subclass
+ /// implements this, else LLDB_INVALID_ADDRESS.
+ //------------------------------------------------------------------
+ virtual lldb::addr_t
+ GetQueueLibdispatchQueueAddress ()
+ {
+ return LLDB_INVALID_ADDRESS;
+ }
+
virtual uint32_t
GetStackFrameCount()
{
@@ -412,6 +534,9 @@ public:
void
DumpUsingSettingsFormat (Stream &strm, uint32_t frame_idx);
+ bool
+ GetDescription (Stream &s, lldb::DescriptionLevel level, bool json_output);
+
//------------------------------------------------------------------
/// Default implementation for stepping into.
///
@@ -422,17 +547,22 @@ public:
/// If true and the frame has debug info, then do a source level
/// step in, else do a single instruction step in.
///
- /// @param[in] avoid_code_without_debug_info
+ /// @param[in] step_in_avoids_code_without_debug_info
/// If \a true, then avoid stepping into code that doesn't have
- /// debug info, else step into any code regardless of wether it
+ /// debug info, else step into any code regardless of whether it
/// has debug info.
///
+ /// @param[in] step_out_avoids_code_without_debug_info
+ /// If \a true, then if you step out to code with no debug info, keep
+ /// stepping out till you get to code with debug info.
+ ///
/// @return
/// An error that describes anything that went wrong
//------------------------------------------------------------------
virtual Error
StepIn (bool source_step,
- bool avoid_code_without_debug_info);
+ LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate,
+ LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
//------------------------------------------------------------------
/// Default implementation for stepping over.
@@ -448,7 +578,8 @@ public:
/// An error that describes anything that went wrong
//------------------------------------------------------------------
virtual Error
- StepOver (bool source_step);
+ StepOver (bool source_step,
+ LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
//------------------------------------------------------------------
/// Default implementation for stepping out.
@@ -487,6 +618,19 @@ public:
virtual lldb::addr_t
GetThreadLocalData (const lldb::ModuleSP module);
+ //------------------------------------------------------------------
+ /// Check whether this thread is safe to run functions
+ ///
+ /// The SystemRuntime may know of certain thread states (functions in
+ /// process of execution, for instance) which can make it unsafe for
+ /// functions to be called.
+ ///
+ /// @return
+ /// True if it is safe to call functions on this thread.
+ /// False if function calls should be avoided on this thread.
+ //------------------------------------------------------------------
+ virtual bool
+ SafeToCallFunctions ();
//------------------------------------------------------------------
// Thread Plan Providers:
@@ -574,14 +718,19 @@ public:
/// @param[in] stop_other_threads
/// \b true if we will stop other threads while we single step this one.
///
+ /// @param[in] step_out_avoids_code_without_debug_info
+ /// If eLazyBoolYes, if the step over steps out it will continue to step out till it comes to a frame with debug info.
+ /// If eLazyBoolCalculate, we will consult the default set in the thread.
+ ///
/// @return
/// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual lldb::ThreadPlanSP
QueueThreadPlanForStepOverRange (bool abort_other_plans,
- const AddressRange &range,
- const SymbolContext &addr_context,
- lldb::RunMode stop_other_threads);
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_other_threads,
+ LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
//------------------------------------------------------------------
/// Queues the plan used to step through an address range, stepping into functions.
@@ -609,19 +758,25 @@ public:
/// @param[in] stop_other_threads
/// \b true if we will stop other threads while we single step this one.
///
- /// @param[in] avoid_code_without_debug_info
- /// If \b true we will step out if we step into code with no debug info.
+ /// @param[in] step_in_avoids_code_without_debug_info
+ /// If eLazyBoolYes we will step out if we step into code with no debug info.
+ /// If eLazyBoolCalculate we will consult the default set in the thread.
+ ///
+ /// @param[in] step_out_avoids_code_without_debug_info
+ /// If eLazyBoolYes, if the step over steps out it will continue to step out till it comes to a frame with debug info.
+ /// If eLazyBoolCalculate, it will consult the default set in the thread.
///
/// @return
/// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual lldb::ThreadPlanSP
QueueThreadPlanForStepInRange (bool abort_other_plans,
- const AddressRange &range,
- const SymbolContext &addr_context,
- const char *step_in_target,
- lldb::RunMode stop_other_threads,
- bool avoid_code_without_debug_info);
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ const char *step_in_target,
+ lldb::RunMode stop_other_threads,
+ LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate,
+ LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
//------------------------------------------------------------------
/// Queue the plan used to step out of the function at the current PC of
@@ -648,6 +803,10 @@ public:
/// @param[in] run_vote
/// See standard meanings for the stop & run votes in ThreadPlan.h.
///
+ /// @param[in] step_out_avoids_code_without_debug_info
+ /// If eLazyBoolYes, if the step over steps out it will continue to step out till it comes to a frame with debug info.
+ /// If eLazyBoolCalculate, it will consult the default set in the thread.
+ ///
/// @return
/// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
@@ -658,7 +817,46 @@ public:
bool stop_other_threads,
Vote stop_vote, // = eVoteYes,
Vote run_vote, // = eVoteNoOpinion);
- uint32_t frame_idx);
+ uint32_t frame_idx,
+ LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
+
+ //------------------------------------------------------------------
+ /// Queue the plan used to step out of the function at the current PC of
+ /// a thread. This version does not consult the should stop here callback, and should only
+ /// be used by other thread plans when they need to retain control of the step out.
+ ///
+ /// @param[in] abort_other_plans
+ /// \b true if we discard the currently queued plans and replace them with this one.
+ /// Otherwise this plan will go on the end of the plan stack.
+ ///
+ /// @param[in] addr_context
+ /// When dealing with stepping through inlined functions the current PC is not enough information to know
+ /// what "step" means. For instance a series of nested inline functions might start at the same address.
+ // The \a addr_context provides the current symbol context the step
+ /// is supposed to be out of.
+ // FIXME: Currently unused.
+ ///
+ /// @param[in] first_insn
+ /// \b true if this is the first instruction of a function.
+ ///
+ /// @param[in] stop_other_threads
+ /// \b true if we will stop other threads while we single step this one.
+ ///
+ /// @param[in] stop_vote
+ /// @param[in] run_vote
+ /// See standard meanings for the stop & run votes in ThreadPlan.h.
+ ///
+ /// @return
+ /// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual lldb::ThreadPlanSP
+ QueueThreadPlanForStepOutNoShouldStop (bool abort_other_plans,
+ SymbolContext *addr_context,
+ bool first_insn,
+ bool stop_other_threads,
+ Vote stop_vote, // = eVoteYes,
+ Vote run_vote, // = eVoteNoOpinion);
+ uint32_t frame_idx);
//------------------------------------------------------------------
/// Gets the plan used to step through the code that steps from a function
@@ -768,6 +966,17 @@ public:
GetReturnValueObject ();
//------------------------------------------------------------------
+ /// Gets the outer-most expression variable from the completed plans
+ ///
+ /// @return
+ /// A ClangExpressionVariableSP, either empty if there is no
+ /// plan completed an expression during the current stop
+ /// or the expression variable that was made for the completed expression.
+ //------------------------------------------------------------------
+ lldb::ClangExpressionVariableSP
+ GetExpressionVariable ();
+
+ //------------------------------------------------------------------
/// Checks whether the given plan is in the completed plans for this
/// stop.
///
@@ -1066,6 +1275,13 @@ protected:
return false;
}
+ // Subclasses that have a way to get an extended info dictionary for this thread should
+ // fill
+ virtual lldb_private::StructuredData::ObjectSP
+ FetchThreadExtendedInfo ()
+ {
+ return StructuredData::ObjectSP();
+ }
lldb::StackFrameListSP
GetStackFrameList ();
@@ -1091,11 +1307,13 @@ protected:
int m_resume_signal; ///< The signal that should be used when continuing this thread.
lldb::StateType m_resume_state; ///< This state is used to force a thread to be suspended from outside the ThreadPlan logic.
lldb::StateType m_temporary_resume_state; ///< This state records what the thread was told to do by the thread plan logic for the current resume.
- /// It gets set in Thread::ShoudResume.
+ /// It gets set in Thread::ShouldResume.
std::unique_ptr<lldb_private::Unwind> m_unwinder_ap;
bool m_destroy_called; // This is used internally to make sure derived Thread classes call DestroyThread.
LazyBool m_override_should_notify;
private:
+ bool m_extended_info_fetched; // Have we tried to retrieve the m_extended_info for this thread?
+ StructuredData::ObjectSP m_extended_info; // The extended info for this thread
//------------------------------------------------------------------
// For Thread only
//------------------------------------------------------------------
diff --git a/include/lldb/Target/ThreadPlan.h b/include/lldb/Target/ThreadPlan.h
index 3c83fd1b9630..1f20841906d3 100644
--- a/include/lldb/Target/ThreadPlan.h
+++ b/include/lldb/Target/ThreadPlan.h
@@ -501,11 +501,26 @@ public:
return m_thread.GetStopInfo ();
}
+ // If the completion of the thread plan stepped out of a function, the return value of the function
+ // might have been captured by the thread plan (currently only ThreadPlanStepOut does this.)
+ // If so, the ReturnValueObject can be retrieved from here.
+
virtual lldb::ValueObjectSP
GetReturnValueObject ()
{
return lldb::ValueObjectSP();
}
+
+ // If the thread plan managing the evaluation of a user expression lives longer than the command
+ // that instigated the expression (generally because the expression evaluation hit a breakpoint, and
+ // the user regained control at that point) a subsequent process control command step/continue/etc. might
+ // complete the expression evaluations. If so, the result of the expression evaluation will show up here.
+
+ virtual lldb::ClangExpressionVariableSP
+ GetExpressionVariable ()
+ {
+ return lldb::ClangExpressionVariableSP();
+ }
// If a thread plan stores the state before it was run, then you might
// want to restore the state when it is done. This will do that job.
@@ -524,6 +539,27 @@ public:
return false;
}
+ virtual bool
+ SetIterationCount (size_t count)
+ {
+ if (m_takes_iteration_count)
+ {
+ // Don't tell me to do something 0 times...
+ if (count == 0)
+ return false;
+ m_iteration_count = count;
+ }
+ return m_takes_iteration_count;
+ }
+
+ virtual size_t
+ GetIterationCount ()
+ {
+ if (!m_takes_iteration_count)
+ return 0;
+ else
+ return m_iteration_count;
+ }
protected:
//------------------------------------------------------------------
// Classes that inherit from ThreadPlan can see and modify these
@@ -578,6 +614,8 @@ protected:
Thread &m_thread;
Vote m_stop_vote;
Vote m_run_vote;
+ bool m_takes_iteration_count = false;
+ int32_t m_iteration_count = 1;
private:
//------------------------------------------------------------------
diff --git a/include/lldb/Target/ThreadPlanCallFunction.h b/include/lldb/Target/ThreadPlanCallFunction.h
index 18f1d0facbf6..12200ab76553 100644
--- a/include/lldb/Target/ThreadPlanCallFunction.h
+++ b/include/lldb/Target/ThreadPlanCallFunction.h
@@ -52,9 +52,6 @@ public:
virtual bool
StopOthers ();
- virtual void
- SetStopOthers (bool new_value);
-
virtual lldb::StateType
GetPlanRunState ();
@@ -128,7 +125,10 @@ public:
m_takedown_done = true;
}
-protected:
+ virtual void
+ SetStopOthers (bool new_value);
+
+protected:
void ReportRegisterState (const char *message);
virtual bool
diff --git a/include/lldb/Target/ThreadPlanCallUserExpression.h b/include/lldb/Target/ThreadPlanCallUserExpression.h
index 5eb7cc1cd452..67ac642de7bd 100644
--- a/include/lldb/Target/ThreadPlanCallUserExpression.h
+++ b/include/lldb/Target/ThreadPlanCallUserExpression.h
@@ -40,21 +40,35 @@ public:
GetDescription (Stream *s, lldb::DescriptionLevel level);
virtual void
- WillPop ()
- {
- ThreadPlanCallFunction::WillPop();
- if (m_user_expression_sp)
- m_user_expression_sp.reset();
- }
+ WillPop ();
virtual lldb::StopInfoSP
GetRealStopInfo();
+ virtual bool
+ MischiefManaged ();
+
+ void
+ TransferExpressionOwnership ()
+ {
+ m_manage_materialization = true;
+ }
+
+ virtual lldb::ClangExpressionVariableSP
+ GetExpressionVariable ()
+ {
+ return m_result_var_sp;
+ }
+
protected:
private:
ClangUserExpression::ClangUserExpressionSP m_user_expression_sp; // This is currently just used to ensure the
// User expression the initiated this ThreadPlan
// lives as long as the thread plan does.
+ bool m_manage_materialization = false;
+ lldb::ClangExpressionVariableSP m_result_var_sp; // If we are left to manage the materialization,
+ // then stuff the result expression variable here.
+
DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallUserExpression);
};
diff --git a/include/lldb/Target/ThreadPlanShouldStopHere.h b/include/lldb/Target/ThreadPlanShouldStopHere.h
index 62068b78ae4e..26e4a1ec4fe7 100644
--- a/include/lldb/Target/ThreadPlanShouldStopHere.h
+++ b/include/lldb/Target/ThreadPlanShouldStopHere.h
@@ -21,8 +21,9 @@ namespace lldb_private {
// This is an interface that ThreadPlans can adopt to allow flexible modifications of the behavior
// when a thread plan comes to a place where it would ordinarily stop. If such modification makes
// sense for your plan, inherit from this class, and when you would be about to stop (in your ShouldStop
-// method), call InvokeShouldStopHereCallback, and if that returns a non-NULL plan, execute that
-// plan instead of stopping.
+// method), call InvokeShouldStopHereCallback, passing in the frame comparison between where the step operation
+// started and where you arrived. If it returns true, then QueueStepOutFromHere will queue the plan
+// to execute instead of stopping.
//
// The classic example of the use of this is ThreadPlanStepInRange not stopping in frames that have
// no debug information.
@@ -34,27 +35,84 @@ namespace lldb_private {
class ThreadPlanShouldStopHere
{
public:
+ struct ThreadPlanShouldStopHereCallbacks
+ {
+ ThreadPlanShouldStopHereCallbacks()
+ {
+ should_stop_here_callback = nullptr;
+ step_from_here_callback = nullptr;
+ }
+
+ ThreadPlanShouldStopHereCallbacks(ThreadPlanShouldStopHereCallback should_stop,
+ ThreadPlanStepFromHereCallback step_from_here)
+ {
+ should_stop_here_callback = should_stop;
+ step_from_here_callback = step_from_here;
+ }
+
+ void
+ Clear()
+ {
+ should_stop_here_callback = nullptr;
+ step_from_here_callback = nullptr;
+ }
+
+ ThreadPlanShouldStopHereCallback should_stop_here_callback;
+ ThreadPlanStepFromHereCallback step_from_here_callback;
+ };
+
enum
{
eNone = 0,
- eAvoidInlines = (1 << 0),
- eAvoidNoDebug = (1 << 1)
+ eAvoidInlines = (1 << 0),
+ eStepInAvoidNoDebug = (1 << 1),
+ eStepOutAvoidNoDebug = (1 << 2)
};
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
+ ThreadPlanShouldStopHere (ThreadPlan *owner);
+
ThreadPlanShouldStopHere (ThreadPlan *owner,
- ThreadPlanShouldStopHereCallback callback = NULL,
+ const ThreadPlanShouldStopHereCallbacks *callbacks,
void *baton = NULL);
virtual
~ThreadPlanShouldStopHere();
-
+
+ // Set the ShouldStopHere callbacks. Pass in null to clear them and have no special behavior (though you
+ // can also call ClearShouldStopHereCallbacks for that purpose. If you pass in a valid pointer, it will
+ // adopt the non-null fields, and any null fields will be set to the default values.
+
void
- SetShouldStopHereCallback (ThreadPlanShouldStopHereCallback callback, void *baton);
+ SetShouldStopHereCallbacks (const ThreadPlanShouldStopHereCallbacks *callbacks, void *baton)
+ {
+ if (callbacks)
+ {
+ m_callbacks = *callbacks;
+ if (!m_callbacks.should_stop_here_callback)
+ m_callbacks.should_stop_here_callback = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback;
+ if (!m_callbacks.step_from_here_callback)
+ m_callbacks.step_from_here_callback = ThreadPlanShouldStopHere::DefaultStepFromHereCallback;
+ }
+ else
+ {
+ ClearShouldStopHereCallbacks ();
+ }
+ m_baton = baton;
+ }
+
+ void
+ ClearShouldStopHereCallbacks()
+ {
+ m_callbacks.Clear();
+ }
+ bool
+ InvokeShouldStopHereCallback (lldb::FrameComparison operation);
+
lldb::ThreadPlanSP
- InvokeShouldStopHereCallback ();
+ CheckShouldStopHereAndQueueStepOut (lldb::FrameComparison operation);
lldb_private::Flags &
GetFlags ()
@@ -69,13 +127,22 @@ public:
}
protected:
+ static bool
+ DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, void *baton);
+
+ static lldb::ThreadPlanSP
+ DefaultStepFromHereCallback (ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, void *baton);
+
+ virtual lldb::ThreadPlanSP
+ QueueStepOutFromHerePlan (Flags &flags, lldb::FrameComparison operation);
+
// Implement this, and call it in the plan's constructor to set the default flags.
virtual void SetFlagsToDefault () = 0;
//------------------------------------------------------------------
// Classes that inherit from ThreadPlanShouldStopHere can see and modify these
//------------------------------------------------------------------
- ThreadPlanShouldStopHereCallback m_callback;
+ ThreadPlanShouldStopHereCallbacks m_callbacks;
void * m_baton;
ThreadPlan *m_owner;
lldb_private::Flags m_flags;
diff --git a/include/lldb/Target/ThreadPlanStepInRange.h b/include/lldb/Target/ThreadPlanStepInRange.h
index 2f741f179bd4..3a22e97e30d0 100644
--- a/include/lldb/Target/ThreadPlanStepInRange.h
+++ b/include/lldb/Target/ThreadPlanStepInRange.h
@@ -30,13 +30,17 @@ public:
ThreadPlanStepInRange (Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others);
-
+ lldb::RunMode stop_others,
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info);
+
ThreadPlanStepInRange (Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
const char *step_into_function_name,
- lldb::RunMode stop_others);
+ lldb::RunMode stop_others,
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info);
virtual
~ThreadPlanStepInRange ();
@@ -54,9 +58,6 @@ public:
m_step_into_target.SetCString(target);
}
- static lldb::ThreadPlanSP
- DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton);
-
static void
SetDefaultFlagValue (uint32_t new_value);
@@ -64,13 +65,26 @@ public:
IsVirtualStep();
protected:
+ static bool
+ DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, void *baton);
+
virtual bool DoWillResume (lldb::StateType resume_state, bool current_plan);
virtual bool
DoPlanExplainsStop (Event *event_ptr);
virtual void
- SetFlagsToDefault ();
+ SetFlagsToDefault ()
+ {
+ GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
+ }
+
+ void
+ SetCallbacks()
+ {
+ ThreadPlanShouldStopHere::ThreadPlanShouldStopHereCallbacks callbacks(ThreadPlanStepInRange::DefaultShouldStopHereCallback, nullptr);
+ SetShouldStopHereCallbacks (&callbacks, nullptr);
+ }
bool
FrameMatchesAvoidCriteria ();
@@ -81,20 +95,23 @@ private:
Thread::QueueThreadPlanForStepOverRange (bool abort_other_plans,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others);
+ lldb::RunMode stop_others,
+ LazyBool avoid_code_without_debug_info);
friend lldb::ThreadPlanSP
Thread::QueueThreadPlanForStepInRange (bool abort_other_plans,
const AddressRange &range,
const SymbolContext &addr_context,
const char *step_in_target,
lldb::RunMode stop_others,
- bool avoid_code_without_debug_info);
-
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info);
+ void SetupAvoidNoDebug(LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info);
// Need an appropriate marker for the current stack so we can tell step out
// from step in.
- static uint32_t s_default_flag_values;
+ static uint32_t s_default_flag_values; // These are the default flag values for the ThreadPlanStepThrough.
lldb::ThreadPlanSP m_sub_plan_sp; // Keep track of the last plan we were running. If it fails, we should stop.
std::unique_ptr<RegularExpression> m_avoid_regexp_ap;
bool m_step_past_prologue; // FIXME: For now hard-coded to true, we could put a switch in for this if there's
diff --git a/include/lldb/Target/ThreadPlanStepInstruction.h b/include/lldb/Target/ThreadPlanStepInstruction.h
index eb4a64bcbc84..86069ffd9eb5 100644
--- a/include/lldb/Target/ThreadPlanStepInstruction.h
+++ b/include/lldb/Target/ThreadPlanStepInstruction.h
@@ -32,6 +32,7 @@ public:
virtual lldb::StateType GetPlanRunState ();
virtual bool WillStop ();
virtual bool MischiefManaged ();
+ virtual bool IsPlanStale ();
protected:
virtual bool DoPlanExplainsStop (Event *event_ptr);
@@ -41,6 +42,7 @@ protected:
bool stop_others,
Vote stop_vote,
Vote run_vote);
+ void SetUpState ();
private:
friend lldb::ThreadPlanSP
diff --git a/include/lldb/Target/ThreadPlanStepOut.h b/include/lldb/Target/ThreadPlanStepOut.h
index 2737978a4edc..8c140dc9d95d 100644
--- a/include/lldb/Target/ThreadPlanStepOut.h
+++ b/include/lldb/Target/ThreadPlanStepOut.h
@@ -16,10 +16,12 @@
// Project includes
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanShouldStopHere.h"
namespace lldb_private {
-class ThreadPlanStepOut : public ThreadPlan
+class ThreadPlanStepOut : public ThreadPlan,
+ public ThreadPlanShouldStopHere
{
public:
ThreadPlanStepOut (Thread &thread,
@@ -28,7 +30,8 @@ public:
bool stop_others,
Vote stop_vote,
Vote run_vote,
- uint32_t frame_idx);
+ uint32_t frame_idx,
+ LazyBool step_out_avoids_code_without_debug_info);
virtual ~ThreadPlanStepOut ();
@@ -48,21 +51,29 @@ public:
}
protected:
+ virtual void
+ SetFlagsToDefault ()
+ {
+ GetFlags().Set(ThreadPlanStepOut::s_default_flag_values);
+ }
+
virtual bool DoPlanExplainsStop (Event *event_ptr);
virtual bool DoWillResume (lldb::StateType resume_state, bool current_plan);
bool QueueInlinedStepPlan (bool queue_now);
private:
- SymbolContext *m_step_from_context;
+ static uint32_t s_default_flag_values; // These are the default flag values for the ThreadPlanStepThrough.
+
lldb::addr_t m_step_from_insn;
StackID m_step_out_to_id;
StackID m_immediate_step_from_id;
lldb::break_id_t m_return_bp_id;
lldb::addr_t m_return_addr;
- bool m_first_insn;
bool m_stop_others;
- lldb::ThreadPlanSP m_step_through_inline_plan_sp;
- lldb::ThreadPlanSP m_step_out_plan_sp;
+ lldb::ThreadPlanSP m_step_out_to_inline_plan_sp; // This plan implements step out to the real function containing
+ // an inlined frame so we can then step out of that.
+ lldb::ThreadPlanSP m_step_through_inline_plan_sp; // This plan then steps past the inlined frame(s).
+ lldb::ThreadPlanSP m_step_out_further_plan_sp; // This plan keeps stepping out if ShouldStopHere told us to.
Function *m_immediate_step_from_function;
lldb::ValueObjectSP m_return_valobj_sp;
@@ -73,8 +84,10 @@ private:
bool stop_others,
Vote stop_vote,
Vote run_vote,
- uint32_t frame_idx);
+ uint32_t frame_idx,
+ LazyBool step_out_avoids_code_without_debug_info);
+ void SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info);
// Need an appropriate marker for the current stack so we can tell step out
// from step in.
diff --git a/include/lldb/Target/ThreadPlanStepOverRange.h b/include/lldb/Target/ThreadPlanStepOverRange.h
index 2cb5288272ea..d47c6c9429d5 100644
--- a/include/lldb/Target/ThreadPlanStepOverRange.h
+++ b/include/lldb/Target/ThreadPlanStepOverRange.h
@@ -21,14 +21,16 @@
namespace lldb_private {
-class ThreadPlanStepOverRange : public ThreadPlanStepRange
+class ThreadPlanStepOverRange : public ThreadPlanStepRange,
+ ThreadPlanShouldStopHere
{
public:
ThreadPlanStepOverRange (Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others);
+ lldb::RunMode stop_others,
+ LazyBool step_out_avoids_no_debug);
virtual ~ThreadPlanStepOverRange ();
@@ -38,9 +40,20 @@ public:
protected:
virtual bool DoPlanExplainsStop (Event *event_ptr);
virtual bool DoWillResume (lldb::StateType resume_state, bool current_plan);
-
+
+ virtual void
+ SetFlagsToDefault ()
+ {
+ GetFlags().Set(ThreadPlanStepOverRange::s_default_flag_values);
+ }
+
+
+
private:
+ static uint32_t s_default_flag_values;
+
+ void SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info);
bool IsEquivalentContext(const SymbolContext &context);
bool m_first_resume;
diff --git a/include/lldb/Target/ThreadPlanStepRange.h b/include/lldb/Target/ThreadPlanStepRange.h
index 486fd6528390..3487e9ad66cb 100644
--- a/include/lldb/Target/ThreadPlanStepRange.h
+++ b/include/lldb/Target/ThreadPlanStepRange.h
@@ -77,6 +77,7 @@ protected:
std::vector<AddressRange> m_address_ranges;
lldb::RunMode m_stop_others;
StackID m_stack_id; // Use the stack ID so we can tell step out from step in.
+ StackID m_parent_stack_id; // Use the parent stack ID so we can identify tail calls and the like.
bool m_no_more_plans; // Need this one so we can tell if we stepped into a call,
// but can't continue, in which case we are done.
bool m_first_run_event; // We want to broadcast only one running event, our first.
diff --git a/include/lldb/Target/UnwindAssembly.h b/include/lldb/Target/UnwindAssembly.h
index 254382ac029d..963949cf07d5 100644
--- a/include/lldb/Target/UnwindAssembly.h
+++ b/include/lldb/Target/UnwindAssembly.h
@@ -33,6 +33,11 @@ public:
UnwindPlan& unwind_plan) = 0;
virtual bool
+ AugmentUnwindPlanFromCallSite (AddressRange& func,
+ Thread& thread,
+ UnwindPlan& unwind_plan) = 0;
+
+ virtual bool
GetFastUnwindPlan (AddressRange& func,
Thread& thread,
UnwindPlan &unwind_plan) = 0;
diff --git a/include/lldb/Utility/CleanUp.h b/include/lldb/Utility/CleanUp.h
index ab15d1999b7d..9dd3ca5fe12b 100644
--- a/include/lldb/Utility/CleanUp.h
+++ b/include/lldb/Utility/CleanUp.h
@@ -27,7 +27,7 @@ namespace lldb_utility {
// file descriptors, opaque handles, pointers, etc). If more complex
// type T objects are desired, we need to probably specialize this class
// to take "const T&" for all input T parameters. Yet if a type T is
-// complex already it might be better to build the cleanup funcionality
+// complex already it might be better to build the cleanup functionality
// into T.
//
// The cleanup function must take one argument that is of type T.
@@ -163,7 +163,7 @@ public:
//----------------------------------------------------------------------
// Cancels the cleanup that would have been called on "m_current_value"
// if it was valid. This function can be used to release the value
- // contained in this object so ownership can be transfered to the caller.
+ // contained in this object so ownership can be transferred to the caller.
//----------------------------------------------------------------------
value_type
release ()
@@ -296,7 +296,7 @@ public:
//----------------------------------------------------------------------
// Cancels the cleanup that would have been called on "m_current_value"
// if it was valid. This function can be used to release the value
- // contained in this object so ownership can be transfered to the caller.
+ // contained in this object so ownership can be transferred to the caller.
//----------------------------------------------------------------------
value_type
release ()
diff --git a/include/lldb/Utility/PseudoTerminal.h b/include/lldb/Utility/PseudoTerminal.h
index c79800fab75c..6ee598cefe08 100644
--- a/include/lldb/Utility/PseudoTerminal.h
+++ b/include/lldb/Utility/PseudoTerminal.h
@@ -23,7 +23,7 @@ namespace lldb_utility {
/// @class PseudoTerminal PseudoTerminal.h "lldb/Core/PseudoTerminal.h"
/// @brief A pseudo terminal helper class.
///
-/// The pseudo terminal class abtracts the use of pseudo terminals on
+/// The pseudo terminal class abstracts the use of pseudo terminals on
/// the host system.
//----------------------------------------------------------------------
class PseudoTerminal
@@ -46,7 +46,7 @@ public:
/// Destructor
///
/// The destructor will close the master and slave file descriptors
- /// if they are valid and ownwership has not been released using
+ /// if they are valid and ownership has not been released using
/// one of:
/// @li PseudoTerminal::ReleaseMasterFileDescriptor()
/// @li PseudoTerminal::ReleaseSaveFileDescriptor()
diff --git a/include/lldb/Utility/SafeMachO.h b/include/lldb/Utility/SafeMachO.h
new file mode 100644
index 000000000000..2a831ed89b80
--- /dev/null
+++ b/include/lldb/Utility/SafeMachO.h
@@ -0,0 +1,113 @@
+//===-- SafeMachO.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_SafeMachO_h_
+#define liblldb_SafeMachO_h_
+
+// This header file is required to work around collisions between the defines in mach/machine.h, and enum members
+// of the same name in llvm's MachO.h. If you want to use llvm/Support/MachO.h, use this file instead.
+// The caveats are:
+// 1) You can only use the MachO.h enums, you can't use the defines. That won't make a difference since the values
+// are the same.
+// 2) If you need any header file that relies on mach/machine.h, you must include that first.
+// 3) This isn't a total solution, it doesn't undef every define that MachO.h has borrowed from various system headers,
+// only the ones that come from mach/machine.h because that is the one we ended up pulling in from various places.
+//
+
+#undef CPU_ARCH_MASK
+#undef CPU_ARCH_ABI64
+
+#undef CPU_TYPE_ANY
+#undef CPU_TYPE_X86
+#undef CPU_TYPE_I386
+#undef CPU_TYPE_X86_64
+#undef CPU_TYPE_MC98000
+#undef CPU_TYPE_ARM
+#undef CPU_TYPE_ARM64
+#undef CPU_TYPE_SPARC
+#undef CPU_TYPE_POWERPC
+#undef CPU_TYPE_POWERPC64
+
+#undef CPU_SUB_TYPE_MASK
+#undef CPU_SUB_TYPE_LIB64
+
+#undef CPU_SUBTYPE_MULTIPLE
+
+#undef CPU_SUBTYPE_I386_ALL
+#undef CPU_SUBTYPE_386
+#undef CPU_SUBTYPE_486
+#undef CPU_SUBTYPE_486SX
+#undef CPU_SUBTYPE_586
+#undef CPU_SUBTYPE_PENT
+#undef CPU_SUBTYPE_PENTPRO
+#undef CPU_SUBTYPE_PENTII_M3
+#undef CPU_SUBTYPE_PENTII_M5
+#undef CPU_SUBTYPE_CELERON
+#undef CPU_SUBTYPE_CELERON_MOBILE
+#undef CPU_SUBTYPE_PENTIUM_3
+#undef CPU_SUBTYPE_PENTIUM_3_M
+#undef CPU_SUBTYPE_PENTIUM_3_XEON
+#undef CPU_SUBTYPE_PENTIUM_M
+#undef CPU_SUBTYPE_PENTIUM_4
+#undef CPU_SUBTYPE_PENTIUM_4_M
+#undef CPU_SUBTYPE_ITANIUM
+#undef CPU_SUBTYPE_ITANIUM_2
+#undef CPU_SUBTYPE_XEON
+#undef CPU_SUBTYPE_XEON_MP
+
+#undef CPU_SUBTYPE_X86_ALL
+#undef CPU_SUBTYPE_X86_64_ALL
+#undef CPU_SUBTYPE_X86_ARCH1
+#undef CPU_SUBTYPE_X86_64_H
+
+#undef CPU_SUBTYPE_INTEL
+#undef CPU_SUBTYPE_INTEL_FAMILY
+#undef CPU_SUBTYPE_INTEL_FAMILY_MAX
+#undef CPU_SUBTYPE_INTEL_MODEL
+#undef CPU_SUBTYPE_INTEL_MODEL_ALL
+
+#undef CPU_SUBTYPE_ARM
+#undef CPU_SUBTYPE_ARM_ALL
+#undef CPU_SUBTYPE_ARM_V4T
+#undef CPU_SUBTYPE_ARM_V6
+#undef CPU_SUBTYPE_ARM_V5
+#undef CPU_SUBTYPE_ARM_V5TEJ
+#undef CPU_SUBTYPE_ARM_XSCALE
+#undef CPU_SUBTYPE_ARM_V7
+
+#undef CPU_SUBTYPE_ARM_V7S
+#undef CPU_SUBTYPE_ARM_V7K
+#undef CPU_SUBTYPE_ARM_V6M
+#undef CPU_SUBTYPE_ARM_V7M
+#undef CPU_SUBTYPE_ARM_V7EM
+
+#undef CPU_SUBTYPE_ARM64_ALL
+
+#undef CPU_SUBTYPE_SPARC_ALL
+
+#undef CPU_SUBTYPE_POWERPC
+#undef CPU_SUBTYPE_POWERPC_ALL
+#undef CPU_SUBTYPE_POWERPC_601
+#undef CPU_SUBTYPE_POWERPC_602
+#undef CPU_SUBTYPE_POWERPC_603
+#undef CPU_SUBTYPE_POWERPC_603e
+#undef CPU_SUBTYPE_POWERPC_603ev
+#undef CPU_SUBTYPE_POWERPC_604
+#undef CPU_SUBTYPE_POWERPC_604e
+#undef CPU_SUBTYPE_POWERPC_620
+#undef CPU_SUBTYPE_POWERPC_750
+#undef CPU_SUBTYPE_POWERPC_7400
+#undef CPU_SUBTYPE_POWERPC_7450
+#undef CPU_SUBTYPE_POWERPC_970
+
+#undef CPU_SUBTYPE_MC980000_ALL
+#undef CPU_SUBTYPE_MC98601
+
+#include "llvm/Support/MachO.h"
+
+#endif // liblldb_SafeMachO_h_
diff --git a/include/lldb/Utility/SharedCluster.h b/include/lldb/Utility/SharedCluster.h
index 991af4b4fa49..3a34d8ddb415 100644
--- a/include/lldb/Utility/SharedCluster.h
+++ b/include/lldb/Utility/SharedCluster.h
@@ -13,6 +13,8 @@
#include "lldb/Utility/SharingPtr.h"
#include "lldb/Host/Mutex.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
namespace lldb_private {
namespace imp
@@ -50,11 +52,12 @@ public:
~ClusterManager ()
{
- size_t n_items = m_objects.size();
- for (size_t i = 0; i < n_items; i++)
+ for (typename llvm::SmallPtrSet<T *, 16>::iterator pos = m_objects.begin(), end = m_objects.end(); pos != end; ++pos)
{
- delete m_objects[i];
+ T *object = *pos;
+ delete object;
}
+
// Decrement refcount should have been called on this ClusterManager,
// and it should have locked the mutex, now we will unlock it before
// we destroy it...
@@ -64,8 +67,7 @@ public:
void ManageObject (T *new_object)
{
Mutex::Locker locker (m_mutex);
- if (!ContainsObject(new_object))
- m_objects.push_back (new_object);
+ m_objects.insert (new_object);
}
typename lldb_private::SharingPtr<T> GetSharedPointer(T *desired_object)
@@ -73,20 +75,13 @@ public:
{
Mutex::Locker locker (m_mutex);
m_external_ref++;
- assert (ContainsObject(desired_object));
+ assert (m_objects.count(desired_object));
}
return typename lldb_private::SharingPtr<T> (desired_object, new imp::shared_ptr_refcount<ClusterManager> (this));
}
private:
- bool ContainsObject (const T *desired_object)
- {
- typename std::vector<T *>::iterator pos, end = m_objects.end();
- pos = std::find(m_objects.begin(), end, desired_object);
- return pos != end;
- }
-
void DecrementRefCount ()
{
m_mutex.Lock();
@@ -99,7 +94,7 @@ private:
friend class imp::shared_ptr_refcount<ClusterManager>;
- std::vector<T *> m_objects;
+ llvm::SmallPtrSet<T *, 16> m_objects;
int m_external_ref;
Mutex m_mutex;
};
diff --git a/include/lldb/Utility/SharingPtr.h b/include/lldb/Utility/SharingPtr.h
index c451ee6e3593..1b5f86bbe2df 100644
--- a/include/lldb/Utility/SharingPtr.h
+++ b/include/lldb/Utility/SharingPtr.h
@@ -15,7 +15,7 @@
// Microsoft Visual C++ currently does not enable std::atomic to work
// in CLR mode - as such we need to "hack around it" for MSVC++ builds only
-// using Windows specific instrinsics instead of the C++11 atomic support
+// using Windows specific intrinsics instead of the C++11 atomic support
#ifdef _MSC_VER
#include <intrin.h>
#else
@@ -69,8 +69,8 @@ public:
private:
virtual void on_zero_shared();
- // Outlaw copy constructor and assignment operator to keep effictive C++
- // warnings down to a minumum
+ // Outlaw copy constructor and assignment operator to keep effective C++
+ // warnings down to a minimum
shared_ptr_pointer (const shared_ptr_pointer &);
shared_ptr_pointer & operator=(const shared_ptr_pointer &);
};
@@ -138,6 +138,7 @@ private:
struct nat {int for_bool_;};
public:
SharingPtr();
+ SharingPtr(std::nullptr_t);
template<class Y> explicit SharingPtr(Y* p);
template<class Y> explicit SharingPtr(Y* p, imp::shared_count *ctrl_block);
template<class Y> SharingPtr(const SharingPtr<Y>& r, element_type *p);
@@ -191,6 +192,14 @@ SharingPtr<T>::SharingPtr()
cntrl_(0)
{
}
+
+template<class T>
+inline
+SharingPtr<T>::SharingPtr(std::nullptr_t)
+: ptr_(0),
+cntrl_(0)
+{
+}
template<class T>
template<class Y>
diff --git a/include/lldb/Utility/StringLexer.h b/include/lldb/Utility/StringLexer.h
new file mode 100644
index 000000000000..42c169c5cf94
--- /dev/null
+++ b/include/lldb/Utility/StringLexer.h
@@ -0,0 +1,62 @@
+//===--------------------- StringLexer.h -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef utility_StringLexer_h_
+#define utility_StringLexer_h_
+
+#include <string>
+#include <list>
+
+namespace lldb_utility {
+
+class StringLexer
+{
+public:
+ typedef std::string::size_type Position;
+ typedef std::string::size_type Size;
+
+ typedef std::string::value_type Character;
+
+ StringLexer (std::string s);
+
+ StringLexer (const StringLexer& rhs);
+
+ Character
+ Peek ();
+
+ bool
+ NextIf (Character c);
+
+ Character
+ Next ();
+
+ bool
+ HasAtLeast (Size s);
+
+ bool
+ HasAny (Character c);
+
+ void
+ PutBack (Character c);
+
+ StringLexer&
+ operator = (const StringLexer& rhs);
+
+private:
+ std::string m_data;
+ Position m_position;
+ std::list<Character> m_putback_data;
+
+ void
+ Consume();
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef utility_StringLexer_h_
diff --git a/include/lldb/lldb-defines.h b/include/lldb/lldb-defines.h
index 82307d2f5310..f8028c793233 100644
--- a/include/lldb/lldb-defines.h
+++ b/include/lldb/lldb-defines.h
@@ -12,6 +12,22 @@
#include "lldb/lldb-types.h"
+#if defined (_WIN32)
+ #if defined(EXPORT_LIBLLDB)
+ #define LLDB_API __declspec(dllexport)
+ #elif defined(IMPORT_LIBLLDB)
+ #define LLDB_API __declspec(dllimport)
+ #else
+ #define LLDB_API
+ #endif
+#else // defined (_MSC_VER)
+ #define LLDB_API
+#endif
+
+#if !defined(INT32_MAX)
+ #define INT32_MAX 2147483647
+#endif
+
#if !defined(UINT32_MAX)
#define UINT32_MAX 4294967295U
#endif
@@ -75,6 +91,7 @@
#define LLDB_INVALID_INDEX32 UINT32_MAX
#define LLDB_INVALID_IVAR_OFFSET UINT32_MAX
#define LLDB_INVALID_IMAGE_TOKEN UINT32_MAX
+#define LLDB_INVALID_MODULE_VERSION UINT32_MAX
#define LLDB_INVALID_REGNUM UINT32_MAX
#define LLDB_INVALID_UID UINT64_MAX
#define LLDB_INVALID_PROCESS_ID 0
@@ -86,7 +103,7 @@
#define LLDB_INVALID_QUEUE_ID 0
//----------------------------------------------------------------------
-/// CPU Type defintions
+/// CPU Type definitions
//----------------------------------------------------------------------
#define LLDB_ARCH_DEFAULT "systemArch"
#define LLDB_ARCH_DEFAULT_32BIT "systemArch32"
@@ -94,7 +111,7 @@
#define LLDB_INVALID_CPUTYPE (0xFFFFFFFEu)
//----------------------------------------------------------------------
-/// Option Set defintions
+/// Option Set definitions
//----------------------------------------------------------------------
// FIXME: I'm sure there's some #define magic that can create all 32 sets on the
// fly. That would have the added benefit of making this unreadable.
@@ -112,7 +129,7 @@
#define LLDB_OPT_SET_10 (1U << 9)
#define LLDB_OPT_SET_FROM_TO(A, B) (((1U << (B)) - 1) ^ (((1U << (A))-1) >> 1))
-#ifdef _WIN32
+#if defined (_WIN32) && !defined (MAX_PATH)
#define MAX_PATH 260
#endif
diff --git a/include/lldb/lldb-enumerations.h b/include/lldb/lldb-enumerations.h
index 347e20f21df6..612487fd4fad 100644
--- a/include/lldb/lldb-enumerations.h
+++ b/include/lldb/lldb-enumerations.h
@@ -39,16 +39,18 @@ namespace lldb {
typedef enum LaunchFlags
{
eLaunchFlagNone = 0u,
- eLaunchFlagExec = (1u << 0), ///< Exec when launching and turn the calling process into a new process
- eLaunchFlagDebug = (1u << 1), ///< Stop as soon as the process launches to allow the process to be debugged
- eLaunchFlagStopAtEntry = (1u << 2), ///< Stop at the program entry point instead of auto-continuing when launching or attaching at entry point
- eLaunchFlagDisableASLR = (1u << 3), ///< Disable Address Space Layout Randomization
- eLaunchFlagDisableSTDIO = (1u << 4), ///< Disable stdio for inferior process (e.g. for a GUI app)
- eLaunchFlagLaunchInTTY = (1u << 5), ///< Launch the process in a new TTY if supported by the host
- eLaunchFlagLaunchInShell= (1u << 6), ///< Launch the process inside a shell to get shell expansion
+ eLaunchFlagExec = (1u << 0), ///< Exec when launching and turn the calling process into a new process
+ eLaunchFlagDebug = (1u << 1), ///< Stop as soon as the process launches to allow the process to be debugged
+ eLaunchFlagStopAtEntry = (1u << 2), ///< Stop at the program entry point instead of auto-continuing when launching or attaching at entry point
+ eLaunchFlagDisableASLR = (1u << 3), ///< Disable Address Space Layout Randomization
+ eLaunchFlagDisableSTDIO = (1u << 4), ///< Disable stdio for inferior process (e.g. for a GUI app)
+ eLaunchFlagLaunchInTTY = (1u << 5), ///< Launch the process in a new TTY if supported by the host
+ eLaunchFlagLaunchInShell= (1u << 6), ///< Launch the process inside a shell to get shell expansion
eLaunchFlagLaunchInSeparateProcessGroup = (1u << 7), ///< Launch the process in a separate process group
- eLaunchFlagsDontMonitorProcess = (1u << 8) ///< If you are going to hand the process off (e.g. to debugserver)
- ///< set this flag so lldb & the handee don't race to reap it.
+ eLaunchFlagDontSetExitStatus = (1u << 8), ///< If you are going to hand the process off (e.g. to debugserver)
+ ///< set this flag so lldb & the handee don't race to set its exit status.
+ eLaunchFlagDetachOnError = (1u << 9) ///< If set, then the client stub should detach rather than killing the debugee
+ ///< if it loses connection with lldb.
} LaunchFlags;
//----------------------------------------------------------------------
@@ -155,13 +157,16 @@ namespace lldb {
//----------------------------------------------------------------------
// Register numbering types
+ // See RegisterContext::ConvertRegisterKindToRegisterNumber to convert
+ // any of these to the lldb internal register numbering scheme
+ // (eRegisterKindLLDB).
//----------------------------------------------------------------------
typedef enum RegisterKind
{
eRegisterKindGCC = 0, // the register numbers seen in eh_frame
eRegisterKindDWARF, // the register numbers seen DWARF
eRegisterKindGeneric, // insn ptr reg, stack ptr reg, etc not specific to any particular target
- eRegisterKindGDB, // the register numbers gdb uses (matches stabs numbers?)
+ eRegisterKindGDB, // the register numbers gdb uses (matches stabs numbers)
eRegisterKindLLDB, // lldb's internal register numbers
kNumRegisterKinds
} RegisterKind;
@@ -200,6 +205,22 @@ namespace lldb {
//----------------------------------------------------------------------
+ // The results of expression evaluation:
+ //----------------------------------------------------------------------
+ typedef enum ExpressionResults
+ {
+ eExpressionCompleted = 0,
+ eExpressionSetupError,
+ eExpressionParseError,
+ eExpressionDiscarded,
+ eExpressionInterrupted,
+ eExpressionHitBreakpoint,
+ eExpressionTimedOut,
+ eExpressionResultUnavailable,
+ eExpressionStoppedForDebug
+ } ExpressionResults;
+
+ //----------------------------------------------------------------------
// Connection Status Types
//----------------------------------------------------------------------
typedef enum ConnectionStatus
@@ -209,7 +230,8 @@ namespace lldb {
eConnectionStatusError, // Check GetError() for details
eConnectionStatusTimedOut, // Request timed out
eConnectionStatusNoConnection, // No connection
- eConnectionStatusLostConnection // Lost connection while connected to a valid connection
+ eConnectionStatusLostConnection, // Lost connection while connected to a valid connection
+ eConnectionStatusInterrupted // Interrupted read
} ConnectionStatus;
typedef enum ErrorType
@@ -217,7 +239,9 @@ namespace lldb {
eErrorTypeInvalid,
eErrorTypeGeneric, ///< Generic errors that can be any value.
eErrorTypeMachKernel, ///< Mach kernel error codes.
- eErrorTypePOSIX ///< POSIX error codes.
+ eErrorTypePOSIX, ///< POSIX error codes.
+ eErrorTypeExpression, ///< These are from the ExpressionResults enum.
+ eErrorTypeWin32 ///< Standard Win32 error codes.
} ErrorType;
@@ -349,6 +373,18 @@ namespace lldb {
eLanguageTypeUPC = 0x0012, ///< Unified Parallel C.
eLanguageTypeD = 0x0013, ///< D.
eLanguageTypePython = 0x0014, ///< Python.
+ eLanguageTypeOpenCL = 0x0015, ///< OpenCL.
+ eLanguageTypeGo = 0x0016, ///< Go.
+ eLanguageTypeModula3 = 0x0017, ///< Modula 3.
+ eLanguageTypeHaskell = 0x0018, ///< Haskell.
+ eLanguageTypeC_plus_plus_03 = 0x0019, ///< ISO C++:2003.
+ eLanguageTypeC_plus_plus_11 = 0x001a, ///< ISO C++:2011.
+ eLanguageTypeOCaml = 0x001b, ///< OCaml.
+ eLanguageTypeRust = 0x001c, ///< Rust.
+ eLanguageTypeC11 = 0x001d, ///< ISO C:2011.
+ eLanguageTypeSwift = 0x001e, ///< Swift.
+ eLanguageTypeJulia = 0x001f, ///< Julia.
+ eLanguageTypeDylan = 0x0020, ///< Dylan.
eNumLanguageTypes
} LanguageType;
@@ -653,14 +689,22 @@ namespace lldb {
} TypeOptions;
//----------------------------------------------------------------------
- // This is the return value for frame comparisons. When frame A pushes
- // frame B onto the stack, frame A is OLDER than frame B.
+ // This is the return value for frame comparisons. If you are comparing frame A to frame B
+ // the following cases arise:
+ // 1) When frame A pushes frame B (or a frame that ends up pushing B) A is Older than B.
+ // 2) When frame A pushed frame B (or if frame A is on the stack but B is not) A is Younger than B
+ // 3) When frame A and frame B have the same StackID, they are Equal.
+ // 4) When frame A and frame B have the same immediate parent frame, but are not equal, the comparision yields
+ // SameParent.
+ // 5) If the two frames are on different threads or processes the comparision is Invalid
+ // 6) If for some reason we can't figure out what went on, we return Unknown.
//----------------------------------------------------------------------
typedef enum FrameComparison
{
eFrameCompareInvalid,
eFrameCompareUnknown,
eFrameCompareEqual,
+ eFrameCompareSameParent,
eFrameCompareYounger,
eFrameCompareOlder
} FrameComparison;
@@ -741,6 +785,71 @@ namespace lldb {
eQueueItemKindBlock
} QueueItemKind;
+ //----------------------------------------------------------------------
+ // Queue type
+ // libdispatch aka Grand Central Dispatch (GCD) queues can be either serial
+ // (executing on one thread) or concurrent (executing on multiple threads).
+ //----------------------------------------------------------------------
+ typedef enum QueueKind
+ {
+ eQueueKindUnknown = 0,
+ eQueueKindSerial,
+ eQueueKindConcurrent
+ } QueueKind;
+
+ //----------------------------------------------------------------------
+ // Expression Evaluation Stages
+ // These are the cancellable stages of expression evaluation, passed to the
+ // expression evaluation callback, so that you can interrupt expression
+ // evaluation at the various points in its lifecycle.
+ //----------------------------------------------------------------------
+ typedef enum ExpressionEvaluationPhase
+ {
+ eExpressionEvaluationParse = 0,
+ eExpressionEvaluationIRGen,
+ eExpressionEvaluationExecution,
+ eExpressionEvaluationComplete
+ } ExpressionEvaluationPhase;
+
+
+ //----------------------------------------------------------------------
+ // Watchpoint Kind
+ // Indicates what types of events cause the watchpoint to fire.
+ // Used by Native*Protocol-related classes.
+ //----------------------------------------------------------------------
+ typedef enum WatchpointKind
+ {
+ eWatchpointKindRead = (1u << 0),
+ eWatchpointKindWrite = (1u << 1)
+ } WatchpointKind;
+
+ typedef enum GdbSignal
+ {
+ eGdbSignalBadAccess = 0x91,
+ eGdbSignalBadInstruction = 0x92,
+ eGdbSignalArithmetic = 0x93,
+ eGdbSignalEmulation = 0x94,
+ eGdbSignalSoftware = 0x95,
+ eGdbSignalBreakpoint = 0x96
+ } GdbRemoteSignal;
+
+ //----------------------------------------------------------------------
+ // Used with SBHost::GetPath (lldb::PathType) to find files that are
+ // related to LLDB on the current host machine. Most files are relative
+ // to LLDB or are in known locations.
+ //----------------------------------------------------------------------
+ typedef enum PathType
+ {
+ ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
+ ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
+ ePathTypeHeaderDir, // Find LLDB header file directory
+ ePathTypePythonDir, // Find Python modules (PYTHONPATH) directory
+ ePathTypeLLDBSystemPlugins, // System plug-ins directory
+ ePathTypeLLDBUserPlugins, // User plug-ins directory
+ ePathTypeLLDBTempSystemDir // The LLDB temp directory for this system that will be cleaned up on exit
+
+ } PathType;
+
} // namespace lldb
diff --git a/include/lldb/lldb-forward.h b/include/lldb/lldb-forward.h
index 43e589e39521..b3d15224acb5 100644
--- a/include/lldb/lldb-forward.h
+++ b/include/lldb/lldb-forward.h
@@ -80,7 +80,6 @@ class Debugger;
class Declaration;
class Disassembler;
struct DumpValueObjectOptions;
-class DynamicLibrary;
class DynamicLoader;
class Editline;
class EmulateInstruction;
@@ -106,7 +105,9 @@ class InlineFunctionInfo;
class Instruction;
class InstructionList;
class IOHandler;
+class IOObject;
class IRExecutionUnit;
+class JITLoader;
class LanguageRuntime;
class SystemRuntime;
class LineTable;
@@ -127,6 +128,7 @@ class OptionGroup;
class OptionGroupOptions;
class OptionGroupPlatform;
class ObjectFile;
+class ObjectFileJITDelegate;
class OperatingSystem;
class Options;
class OptionValue;
@@ -242,9 +244,12 @@ class TypeImpl;
class TypeList;
class TypeListImpl;
class TypeMemberImpl;
+class TypeEnumMemberImpl;
+class TypeEnumMemberListImpl;
class TypeNameSpecifierImpl;
class TypePair;
class UUID;
+class UnixSignals;
class Unwind;
class UnwindAssembly;
class UnwindPlan;
@@ -295,7 +300,6 @@ namespace lldb {
typedef std::shared_ptr<lldb_private::Debugger> DebuggerSP;
typedef std::weak_ptr<lldb_private::Debugger> DebuggerWP;
typedef std::shared_ptr<lldb_private::Disassembler> DisassemblerSP;
- typedef std::shared_ptr<lldb_private::DynamicLibrary> DynamicLibrarySP;
typedef std::shared_ptr<lldb_private::DynamicLoader> DynamicLoaderSP;
typedef std::shared_ptr<lldb_private::Event> EventSP;
typedef std::shared_ptr<lldb_private::ExecutionContextRef> ExecutionContextRefSP;
@@ -305,6 +309,8 @@ namespace lldb {
typedef std::shared_ptr<lldb_private::InlineFunctionInfo> InlineFunctionInfoSP;
typedef std::shared_ptr<lldb_private::Instruction> InstructionSP;
typedef std::shared_ptr<lldb_private::IOHandler> IOHandlerSP;
+ typedef std::shared_ptr<lldb_private::IOObject> IOObjectSP;
+ typedef std::shared_ptr<lldb_private::JITLoader> JITLoaderSP;
typedef std::shared_ptr<lldb_private::LanguageRuntime> LanguageRuntimeSP;
typedef std::shared_ptr<lldb_private::SystemRuntime> SystemRuntimeSP;
typedef std::shared_ptr<lldb_private::LineTable> LineTableSP;
@@ -314,6 +320,8 @@ namespace lldb {
typedef std::weak_ptr<lldb_private::Module> ModuleWP;
typedef std::shared_ptr<lldb_private::ObjectFile> ObjectFileSP;
typedef std::weak_ptr<lldb_private::ObjectFile> ObjectFileWP;
+ typedef std::shared_ptr<lldb_private::ObjectFileJITDelegate> ObjectFileJITDelegateSP;
+ typedef std::weak_ptr<lldb_private::ObjectFileJITDelegate> ObjectFileJITDelegateWP;
typedef std::shared_ptr<lldb_private::OptionValue> OptionValueSP;
typedef std::weak_ptr<lldb_private::OptionValue> OptionValueWP;
typedef std::shared_ptr<lldb_private::OptionValueArch> OptionValueArchSP;
@@ -377,6 +385,7 @@ namespace lldb {
typedef std::weak_ptr<lldb_private::Type> TypeWP;
typedef std::shared_ptr<lldb_private::TypeCategoryImpl> TypeCategoryImplSP;
typedef std::shared_ptr<lldb_private::TypeImpl> TypeImplSP;
+ typedef std::shared_ptr<lldb_private::TypeEnumMemberImpl> TypeEnumMemberImplSP;
typedef std::shared_ptr<lldb_private::TypeFilterImpl> TypeFilterImplSP;
typedef std::shared_ptr<lldb_private::TypeFormatImpl> TypeFormatImplSP;
typedef std::shared_ptr<lldb_private::TypeNameSpecifierImpl> TypeNameSpecifierImplSP;
diff --git a/include/lldb/lldb-private-enumerations.h b/include/lldb/lldb-private-enumerations.h
index c2273f5dfe2e..ee1589fe24ed 100644
--- a/include/lldb/lldb-private-enumerations.h
+++ b/include/lldb/lldb-private-enumerations.h
@@ -105,40 +105,6 @@ typedef enum SortOrder
eSortOrderByName
} SortOrder;
-
-//----------------------------------------------------------------------
-// Used in conjunction with Host::GetLLDBPath () to find files that
-// are related to
-//----------------------------------------------------------------------
-typedef enum PathType
-{
- ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
- ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
- ePathTypeHeaderDir, // Find LLDB header file directory
- ePathTypePythonDir, // Find Python modules (PYTHONPATH) directory
- ePathTypeLLDBSystemPlugins, // System plug-ins directory
- ePathTypeLLDBUserPlugins, // User plug-ins directory
- ePathTypeLLDBTempSystemDir // The LLDB temp directory for this system
-
-} PathType;
-
-
-//----------------------------------------------------------------------
-// We can execute ThreadPlans on one thread with various fall-back modes
-// (try other threads after timeout, etc.) This enum gives the result of
-// thread plan executions.
-//----------------------------------------------------------------------
-typedef enum ExecutionResults
-{
- eExecutionSetupError,
- eExecutionCompleted,
- eExecutionDiscarded,
- eExecutionInterrupted,
- eExecutionHitBreakpoint,
- eExecutionTimedOut,
- eExecutionStoppedForDebug
-} ExecutionResults;
-
typedef enum ObjCRuntimeVersions {
eObjC_VersionUnknown = 0,
eAppleObjC_V1 = 1,
@@ -178,7 +144,7 @@ typedef enum NameMatchType
typedef enum InstructionType
{
eInstructionTypeAny, // Support for any instructions at all (at least one)
- eInstructionTypePrologueEpilogue, // All prologue and epilogue instructons that push and pop register values and modify sp/fp
+ eInstructionTypePrologueEpilogue, // All prologue and epilogue instructions that push and pop register values and modify sp/fp
eInstructionTypePCModifying, // Any instruction that modifies the program counter/instruction pointer
eInstructionTypeAll // All instructions of any kind
@@ -262,6 +228,16 @@ enum class LineStatus {
Done // Lines are complete
};
+//----------------------------------------------------------------------
+// Exit Type for inferior processes
+//----------------------------------------------------------------------
+typedef enum ExitType {
+ eExitTypeInvalid,
+ eExitTypeExit, // The exit status represents the return code from normal program exit (i.e. WIFEXITED() was true)
+ eExitTypeSignal, // The exit status represents the signal number that caused the program to exit (i.e. WIFSIGNALED() was true)
+ eExitTypeStop, // The exit status represents the stop signal that caused the program to exit (i.e. WIFSTOPPED() was true)
+} ExitType;
+
} // namespace lldb_private
diff --git a/include/lldb/lldb-private-forward.h b/include/lldb/lldb-private-forward.h
new file mode 100644
index 000000000000..424aa4cc53f4
--- /dev/null
+++ b/include/lldb/lldb-private-forward.h
@@ -0,0 +1,41 @@
+//===-- lldb-private-forward.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_lldb_private_forward_h_
+#define LLDB_lldb_private_forward_h_
+
+#if defined(__cplusplus)
+
+#include <memory>
+
+namespace lldb_private
+{
+ // ---------------------------------------------------------------
+ // Class forward decls.
+ // ---------------------------------------------------------------
+ class NativeBreakpoint;
+ class NativeBreakpointList;
+ class NativeProcessProtocol;
+ class NativeRegisterContext;
+ class NativeThreadProtocol;
+ class UnixSignals;
+
+ // ---------------------------------------------------------------
+ // SP/WP decls.
+ // ---------------------------------------------------------------
+ typedef std::shared_ptr<NativeBreakpoint> NativeBreakpointSP;
+ typedef std::shared_ptr<lldb_private::NativeProcessProtocol> NativeProcessProtocolSP;
+ typedef std::weak_ptr<lldb_private::NativeProcessProtocol> NativeProcessProtocolWP;
+ typedef std::shared_ptr<lldb_private::NativeRegisterContext> NativeRegisterContextSP;
+ typedef std::shared_ptr<lldb_private::NativeThreadProtocol> NativeThreadProtocolSP;
+ typedef std::shared_ptr<lldb_private::UnixSignals> UnixSignalsSP;
+}
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef LLDB_lldb_private_forward_h_
diff --git a/include/lldb/lldb-private-interfaces.h b/include/lldb/lldb-private-interfaces.h
index 5a2da8989f35..3251d6a9fe6c 100644
--- a/include/lldb/lldb-private-interfaces.h
+++ b/include/lldb/lldb-private-interfaces.h
@@ -19,10 +19,12 @@ namespace lldb_private
typedef lldb::ABISP (*ABICreateInstance) (const ArchSpec &arch);
typedef Disassembler* (*DisassemblerCreateInstance) (const ArchSpec &arch, const char *flavor);
typedef DynamicLoader* (*DynamicLoaderCreateInstance) (Process* process, bool force);
+ typedef lldb::JITLoaderSP (*JITLoaderCreateInstance) (Process *process, bool force);
typedef ObjectContainer* (*ObjectContainerCreateInstance) (const lldb::ModuleSP &module_sp, lldb::DataBufferSP& data_sp, lldb::offset_t data_offset, const FileSpec *file, lldb::offset_t offset, lldb::offset_t length);
typedef size_t (*ObjectFileGetModuleSpecifications) (const FileSpec &file, lldb::DataBufferSP& data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, ModuleSpecList &module_specs);
typedef ObjectFile* (*ObjectFileCreateInstance) (const lldb::ModuleSP &module_sp, lldb::DataBufferSP& data_sp, lldb::offset_t data_offset, const FileSpec* file, lldb::offset_t file_offset, lldb::offset_t length);
typedef ObjectFile* (*ObjectFileCreateMemoryInstance) (const lldb::ModuleSP &module_sp, lldb::DataBufferSP& data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t offset);
+ typedef bool (*ObjectFileSaveCore) (const lldb::ProcessSP &process_sp, const FileSpec &outfile, Error &error);
typedef LogChannel* (*LogChannelCreateInstance) ();
typedef EmulateInstruction * (*EmulateInstructionCreateInstance) (const ArchSpec &arch, InstructionType inst_type);
typedef OperatingSystem* (*OperatingSystemCreateInstance) (Process *process, bool force);
@@ -34,10 +36,10 @@ namespace lldb_private
typedef SymbolVendor* (*SymbolVendorCreateInstance) (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm); // Module can be NULL for default system symbol vendor
typedef bool (*BreakpointHitCallback) (void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
typedef bool (*WatchpointHitCallback) (void *baton, StoppointCallbackContext *context, lldb::user_id_t watch_id);
- typedef lldb::ThreadPlanSP (*ThreadPlanShouldStopHereCallback) (ThreadPlan *current_plan, Flags &flags, void *baton);
+ typedef bool (*ThreadPlanShouldStopHereCallback) (ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, void *baton);
+ typedef lldb::ThreadPlanSP (*ThreadPlanStepFromHereCallback) (ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, void *baton);
typedef UnwindAssembly* (*UnwindAssemblyCreateInstance) (const ArchSpec &arch);
typedef int (*ComparisonFunction)(const void *, const void *);
- typedef bool (*CommandOverrideCallback)(void *baton, const char **argv);
typedef void (*DebuggerInitializeCallback)(Debugger &debugger);
} // namespace lldb_private
diff --git a/include/lldb/lldb-private-log.h b/include/lldb/lldb-private-log.h
index 9d8d735dcf41..dc37ae2c7c42 100644
--- a/include/lldb/lldb-private-log.h
+++ b/include/lldb/lldb-private-log.h
@@ -46,6 +46,7 @@
#define LIBLLDB_LOG_OS (1u << 24)
#define LIBLLDB_LOG_PLATFORM (1u << 25)
#define LIBLLDB_LOG_SYSTEM_RUNTIME (1u << 26)
+#define LIBLLDB_LOG_JIT_LOADER (1u << 27)
#define LIBLLDB_LOG_ALL (UINT32_MAX)
#define LIBLLDB_LOG_DEFAULT (LIBLLDB_LOG_PROCESS |\
LIBLLDB_LOG_THREAD |\
diff --git a/include/lldb/lldb-private-types.h b/include/lldb/lldb-private-types.h
index 4340af114be3..12a9324008d8 100644
--- a/include/lldb/lldb-private-types.h
+++ b/include/lldb/lldb-private-types.h
@@ -16,6 +16,9 @@
namespace lldb_private
{
+ class Platform;
+ class ExecutionContext;
+
//----------------------------------------------------------------------
// Every register is described in detail including its name, alternate
// name (optional), encoding, size in bytes and the default display
@@ -51,8 +54,16 @@ namespace lldb_private
const char *string_value;
const char *usage;
} OptionEnumValueElement;
+
+ struct OptionValidator
+ {
+ virtual ~OptionValidator() { }
+ virtual bool IsValid(Platform &platform, const ExecutionContext &target) const = 0;
+ virtual const char * ShortConditionString() const = 0;
+ virtual const char * LongConditionString() const = 0;
+ };
- typedef struct
+ struct OptionDefinition
{
uint32_t usage_mask; // Used to mark options that can be used together. If (1 << n & usage_mask) != 0
// then this option belongs to option set n.
@@ -60,12 +71,13 @@ namespace lldb_private
const char *long_option; // Full name for this option.
int short_option; // Single character for this option.
int option_has_arg; // no_argument, required_argument or optional_argument
+ OptionValidator* validator; // If non-NULL, option is valid iff |validator->IsValid()|, otherwise always valid.
OptionEnumValueElement *enum_values; // If non-NULL an array of enum values.
uint32_t completion_type; // Cookie the option class can use to do define the argument completion.
lldb::CommandArgumentType argument_type; // Type of argument this option takes
const char *usage_text; // Full text explaining what this options does and what (if any) argument to
// pass it.
- } OptionDefinition;
+ };
} // namespace lldb_private
diff --git a/include/lldb/lldb-python.h b/include/lldb/lldb-python.h
index ce5c8176a3c3..c8ef054f60e1 100644
--- a/include/lldb/lldb-python.h
+++ b/include/lldb/lldb-python.h
@@ -13,13 +13,19 @@
// Python.h needs to be included before any system headers in order to avoid redefinition of macros
#ifdef LLDB_DISABLE_PYTHON
-
// Python is disabled in this build
-
#else
-
-#include <Python.h>
-
+ #if defined(__linux__)
+ // features.h will define _POSIX_C_SOURCE if _GNU_SOURCE is defined. This value
+ // may be different from the value that Python defines it to be which results
+ // in a warning. Undefine _POSIX_C_SOURCE before including Python.h The same
+ // holds for _XOPEN_SOURCE.
+ #undef _POSIX_C_SOURCE
+ #undef _XOPEN_SOURCE
+ #endif
+
+ // Include python for non windows machines
+ #include <Python.h>
#endif // LLDB_DISABLE_PYTHON
#endif // LLDB_lldb_python_h_
diff --git a/include/lldb/lldb-types.h b/include/lldb/lldb-types.h
index 5851b5d3f923..fee920f5b198 100644
--- a/include/lldb/lldb-types.h
+++ b/include/lldb/lldb-types.h
@@ -49,37 +49,46 @@ namespace lldb
typedef void* mutex_t;
typedef void* condition_t;
typedef void* rwlock_t;
+ typedef void* process_t; // Process type is HANDLE
typedef uintptr_t thread_t; // Host thread type
typedef uint32_t thread_key_t;
typedef void * thread_arg_t; // Host thread argument type
typedef unsigned thread_result_t; // Host thread result type
typedef thread_result_t (*thread_func_t)(void *); // Host thread function type
- typedef void (*LogOutputCallback) (const char *, void *baton);
- typedef bool (*CommandOverrideCallback)(void *baton, const char **argv);
}
#else
#include <pthread.h>
-namespace lldb {
- //----------------------------------------------------------------------
- // MacOSX Types
- //----------------------------------------------------------------------
- typedef ::pthread_mutex_t mutex_t;
- typedef pthread_cond_t condition_t;
- typedef pthread_rwlock_t rwlock_t;
- typedef pthread_t thread_t; // Host thread type
- typedef pthread_key_t thread_key_t;
- typedef void * thread_arg_t; // Host thread argument type
- typedef void * thread_result_t; // Host thread result type
- typedef void * (*thread_func_t)(void *); // Host thread function type
- typedef void (*LogOutputCallback) (const char *, void *baton);
- typedef bool (*CommandOverrideCallback)(void *baton, const char **argv);
+namespace lldb
+{
+ //----------------------------------------------------------------------
+ // MacOSX Types
+ //----------------------------------------------------------------------
+ typedef ::pthread_mutex_t mutex_t;
+ typedef pthread_cond_t condition_t;
+ typedef pthread_rwlock_t rwlock_t;
+ typedef uint64_t process_t; // Process type is just a pid.
+ typedef pthread_t thread_t; // Host thread type
+ typedef pthread_key_t thread_key_t;
+ typedef void * thread_arg_t; // Host thread argument type
+ typedef void * thread_result_t; // Host thread result type
+ typedef void * (*thread_func_t)(void *); // Host thread function type
} // namespace lldb
#endif
+namespace lldb
+{
+ typedef void (*LogOutputCallback) (const char *, void *baton);
+ typedef bool (*CommandOverrideCallback)(void *baton, const char **argv);
+ typedef bool (*CommandOverrideCallbackWithResult)(void *baton,
+ const char **argv,
+ lldb_private::CommandReturnObject &result);
+ typedef bool (*ExpressionCancelCallback) (ExpressionEvaluationPhase phase, void *baton);
+}
+
#define LLDB_INVALID_HOST_THREAD ((lldb::thread_t)NULL)
#define IS_VALID_LLDB_HOST_THREAD(t) ((t) != LLDB_INVALID_HOST_THREAD)
diff --git a/source/API/SBAddress.cpp b/source/API/SBAddress.cpp
index 799c90907634..6aec0722169f 100644
--- a/source/API/SBAddress.cpp
+++ b/source/API/SBAddress.cpp
@@ -127,13 +127,15 @@ SBAddress::GetLoadAddress (const SBTarget &target) const
addr = m_opaque_ap->GetLoadAddress (target_sp.get());
}
}
-
+
if (log)
{
if (addr == LLDB_INVALID_ADDRESS)
- log->Printf ("SBAddress::GetLoadAddress (SBTarget(%p)) => LLDB_INVALID_ADDRESS", target_sp.get());
+ log->Printf ("SBAddress::GetLoadAddress (SBTarget(%p)) => LLDB_INVALID_ADDRESS",
+ static_cast<void*>(target_sp.get()));
else
- log->Printf ("SBAddress::GetLoadAddress (SBTarget(%p)) => 0x%" PRIx64, target_sp.get(), addr);
+ log->Printf ("SBAddress::GetLoadAddress (SBTarget(%p)) => 0x%" PRIx64,
+ static_cast<void*>(target_sp.get()), addr);
}
return addr;
diff --git a/source/API/SBBreakpoint.cpp b/source/API/SBBreakpoint.cpp
index fbdc0e32f498..a950ca934c68 100644
--- a/source/API/SBBreakpoint.cpp
+++ b/source/API/SBBreakpoint.cpp
@@ -19,9 +19,12 @@
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Address.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
@@ -121,9 +124,11 @@ SBBreakpoint::GetID () const
if (log)
{
if (break_id == LLDB_INVALID_BREAK_ID)
- log->Printf ("SBBreakpoint(%p)::GetID () => LLDB_INVALID_BREAK_ID", m_opaque_sp.get());
+ log->Printf ("SBBreakpoint(%p)::GetID () => LLDB_INVALID_BREAK_ID",
+ static_cast<void*>(m_opaque_sp.get()));
else
- log->Printf ("SBBreakpoint(%p)::GetID () => %u", m_opaque_sp.get(), break_id);
+ log->Printf ("SBBreakpoint(%p)::GetID () => %u",
+ static_cast<void*>(m_opaque_sp.get()), break_id);
}
return break_id;
@@ -133,7 +138,12 @@ SBBreakpoint::GetID () const
bool
SBBreakpoint::IsValid() const
{
- return (bool) m_opaque_sp;
+ if (!m_opaque_sp)
+ return false;
+ else if (m_opaque_sp->GetTarget().GetBreakpointByID(m_opaque_sp->GetID()))
+ return true;
+ else
+ return false;
}
void
@@ -222,7 +232,8 @@ SBBreakpoint::SetEnabled (bool enable)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::SetEnabled (enabled=%i)", m_opaque_sp.get(), enable);
+ log->Printf ("SBBreakpoint(%p)::SetEnabled (enabled=%i)",
+ static_cast<void*>(m_opaque_sp.get()), enable);
if (m_opaque_sp)
{
@@ -249,7 +260,8 @@ SBBreakpoint::SetOneShot (bool one_shot)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::SetOneShot (one_shot=%i)", m_opaque_sp.get(), one_shot);
+ log->Printf ("SBBreakpoint(%p)::SetOneShot (one_shot=%i)",
+ static_cast<void*>(m_opaque_sp.get()), one_shot);
if (m_opaque_sp)
{
@@ -288,8 +300,9 @@ SBBreakpoint::SetIgnoreCount (uint32_t count)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::SetIgnoreCount (count=%u)", m_opaque_sp.get(), count);
-
+ log->Printf ("SBBreakpoint(%p)::SetIgnoreCount (count=%u)",
+ static_cast<void*>(m_opaque_sp.get()), count);
+
if (m_opaque_sp)
{
Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
@@ -330,7 +343,8 @@ SBBreakpoint::GetHitCount () const
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::GetHitCount () => %u", m_opaque_sp.get(), count);
+ log->Printf ("SBBreakpoint(%p)::GetHitCount () => %u",
+ static_cast<void*>(m_opaque_sp.get()), count);
return count;
}
@@ -347,7 +361,8 @@ SBBreakpoint::GetIgnoreCount () const
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::GetIgnoreCount () => %u", m_opaque_sp.get(), count);
+ log->Printf ("SBBreakpoint(%p)::GetIgnoreCount () => %u",
+ static_cast<void*>(m_opaque_sp.get()), count);
return count;
}
@@ -362,7 +377,8 @@ SBBreakpoint::SetThreadID (tid_t tid)
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::SetThreadID (tid=0x%4.4" PRIx64 ")", m_opaque_sp.get(), tid);
+ log->Printf ("SBBreakpoint(%p)::SetThreadID (tid=0x%4.4" PRIx64 ")",
+ static_cast<void*>(m_opaque_sp.get()), tid);
}
@@ -378,7 +394,8 @@ SBBreakpoint::GetThreadID ()
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::GetThreadID () => 0x%4.4" PRIx64, m_opaque_sp.get(), tid);
+ log->Printf ("SBBreakpoint(%p)::GetThreadID () => 0x%4.4" PRIx64,
+ static_cast<void*>(m_opaque_sp.get()), tid);
return tid;
}
@@ -387,7 +404,8 @@ SBBreakpoint::SetThreadIndex (uint32_t index)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::SetThreadIndex (%u)", m_opaque_sp.get(), index);
+ log->Printf ("SBBreakpoint(%p)::SetThreadIndex (%u)",
+ static_cast<void*>(m_opaque_sp.get()), index);
if (m_opaque_sp)
{
Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
@@ -408,18 +426,19 @@ SBBreakpoint::GetThreadIndex() const
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::GetThreadIndex () => %u", m_opaque_sp.get(), thread_idx);
+ log->Printf ("SBBreakpoint(%p)::GetThreadIndex () => %u",
+ static_cast<void*>(m_opaque_sp.get()), thread_idx);
return thread_idx;
}
-
void
SBBreakpoint::SetThreadName (const char *thread_name)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::SetThreadName (%s)", m_opaque_sp.get(), thread_name);
+ log->Printf ("SBBreakpoint(%p)::SetThreadName (%s)",
+ static_cast<void*>(m_opaque_sp.get()), thread_name);
if (m_opaque_sp)
{
@@ -441,7 +460,8 @@ SBBreakpoint::GetThreadName () const
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::GetThreadName () => %s", m_opaque_sp.get(), name);
+ log->Printf ("SBBreakpoint(%p)::GetThreadName () => %s",
+ static_cast<void*>(m_opaque_sp.get()), name);
return name;
}
@@ -451,7 +471,8 @@ SBBreakpoint::SetQueueName (const char *queue_name)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::SetQueueName (%s)", m_opaque_sp.get(), queue_name);
+ log->Printf ("SBBreakpoint(%p)::SetQueueName (%s)",
+ static_cast<void*>(m_opaque_sp.get()), queue_name);
if (m_opaque_sp)
{
Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
@@ -472,7 +493,8 @@ SBBreakpoint::GetQueueName () const
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::GetQueueName () => %s", m_opaque_sp.get(), name);
+ log->Printf ("SBBreakpoint(%p)::GetQueueName () => %s",
+ static_cast<void*>(m_opaque_sp.get()), name);
return name;
}
@@ -488,7 +510,9 @@ SBBreakpoint::GetNumResolvedLocations() const
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::GetNumResolvedLocations () => %" PRIu64, m_opaque_sp.get(), (uint64_t)num_resolved);
+ log->Printf ("SBBreakpoint(%p)::GetNumResolvedLocations () => %" PRIu64,
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<uint64_t>(num_resolved));
return num_resolved;
}
@@ -503,7 +527,9 @@ SBBreakpoint::GetNumLocations() const
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBreakpoint(%p)::GetNumLocations () => %" PRIu64, m_opaque_sp.get(), (uint64_t)num_locs);
+ log->Printf ("SBBreakpoint(%p)::GetNumLocations () => %" PRIu64,
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<uint64_t>(num_locs));
return num_locs;
}
@@ -567,9 +593,14 @@ void
SBBreakpoint::SetCallback (BreakpointHitCallback callback, void *baton)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
if (log)
- log->Printf ("SBBreakpoint(%p)::SetCallback (callback=%p, baton=%p)", m_opaque_sp.get(), callback, baton);
+ {
+ void *pointer = &callback;
+ log->Printf ("SBBreakpoint(%p)::SetCallback (callback=%p, baton=%p)",
+ static_cast<void*>(m_opaque_sp.get()),
+ *static_cast<void**>(&pointer), static_cast<void*>(baton));
+ }
if (m_opaque_sp)
{
@@ -579,6 +610,48 @@ SBBreakpoint::SetCallback (BreakpointHitCallback callback, void *baton)
}
}
+void
+SBBreakpoint::SetScriptCallbackFunction (const char *callback_function_name)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::SetScriptCallbackFunction (callback=%s)",
+ static_cast<void*>(m_opaque_sp.get()),
+ callback_function_name);
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ BreakpointOptions *bp_options = m_opaque_sp->GetOptions();
+ m_opaque_sp->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter()->SetBreakpointCommandCallbackFunction (bp_options,
+ callback_function_name);
+ }
+}
+
+SBError
+SBBreakpoint::SetScriptCallbackBody (const char *callback_body_text)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::SetScriptCallbackBody: callback body:\n%s)",
+ static_cast<void*>(m_opaque_sp.get()), callback_body_text);
+
+ SBError sb_error;
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ BreakpointOptions *bp_options = m_opaque_sp->GetOptions();
+ Error error = m_opaque_sp->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
+ callback_body_text);
+ sb_error.SetError(error);
+ }
+ else
+ sb_error.SetErrorString("invalid breakpoint");
+
+ return sb_error;
+}
lldb_private::Breakpoint *
SBBreakpoint::operator->() const
diff --git a/source/API/SBBreakpointLocation.cpp b/source/API/SBBreakpointLocation.cpp
index 6fdf59f38b4a..4390e9ad737a 100644
--- a/source/API/SBBreakpointLocation.cpp
+++ b/source/API/SBBreakpointLocation.cpp
@@ -17,10 +17,13 @@
#include "lldb/lldb-defines.h"
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Target/ThreadSpec.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadSpec.h"
@@ -43,7 +46,9 @@ SBBreakpointLocation::SBBreakpointLocation (const lldb::BreakpointLocationSP &br
SBStream sstr;
GetDescription (sstr, lldb::eDescriptionLevelBrief);
log->Printf ("SBBreakpointLocation::SBBreakpointLocaiton (const lldb::BreakpointLocationsSP &break_loc_sp"
- "=%p) => this.sp = %p (%s)", break_loc_sp.get(), m_opaque_sp.get(), sstr.GetData());
+ "=%p) => this.sp = %p (%s)",
+ static_cast<void*>(break_loc_sp.get()),
+ static_cast<void*>(m_opaque_sp.get()), sstr.GetData());
}
}
@@ -160,6 +165,49 @@ SBBreakpointLocation::GetCondition ()
}
void
+SBBreakpointLocation::SetScriptCallbackFunction (const char *callback_function_name)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBreakpointLocation(%p)::SetScriptCallbackFunction (callback=%s)",
+ static_cast<void*>(m_opaque_sp.get()),
+ callback_function_name);
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ BreakpointOptions *bp_options = m_opaque_sp->GetLocationOptions();
+ m_opaque_sp->GetBreakpoint().GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter()->SetBreakpointCommandCallbackFunction (bp_options,
+ callback_function_name);
+ }
+}
+
+SBError
+SBBreakpointLocation::SetScriptCallbackBody (const char *callback_body_text)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::SetScriptCallbackBody: callback body:\n%s)",
+ static_cast<void*>(m_opaque_sp.get()), callback_body_text);
+
+ SBError sb_error;
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ BreakpointOptions *bp_options = m_opaque_sp->GetLocationOptions();
+ Error error = m_opaque_sp->GetBreakpoint().GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
+ callback_body_text);
+ sb_error.SetError(error);
+ }
+ else
+ sb_error.SetErrorString("invalid breakpoint");
+
+ return sb_error;
+}
+
+void
SBBreakpointLocation::SetThreadID (tid_t thread_id)
{
if (m_opaque_sp)
@@ -312,8 +360,9 @@ SBBreakpointLocation::GetBreakpoint ()
{
SBStream sstr;
sb_bp.GetDescription (sstr);
- log->Printf ("SBBreakpointLocation(%p)::GetBreakpoint () => SBBreakpoint(%p) %s",
- m_opaque_sp.get(), sb_bp.get(), sstr.GetData());
+ log->Printf ("SBBreakpointLocation(%p)::GetBreakpoint () => SBBreakpoint(%p) %s",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(sb_bp.get()), sstr.GetData());
}
return sb_bp;
}
diff --git a/source/API/SBBroadcaster.cpp b/source/API/SBBroadcaster.cpp
index 7168305ac80b..73eac5183f8a 100644
--- a/source/API/SBBroadcaster.cpp
+++ b/source/API/SBBroadcaster.cpp
@@ -33,7 +33,7 @@ SBBroadcaster::SBBroadcaster (const char *name) :
if (log)
log->Printf ("SBBroadcaster::SBBroadcaster (name=\"%s\") => SBBroadcaster(%p)",
- name, m_opaque_ptr);
+ name, static_cast<void*>(m_opaque_ptr));
}
SBBroadcaster::SBBroadcaster (lldb_private::Broadcaster *broadcaster, bool owns) :
@@ -43,8 +43,9 @@ SBBroadcaster::SBBroadcaster (lldb_private::Broadcaster *broadcaster, bool owns)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API | LIBLLDB_LOG_VERBOSE));
if (log)
- log->Printf ("SBBroadcaster::SBBroadcaster (broadcaster=%p, bool owns=%i) => SBBroadcaster(%p)",
- broadcaster, owns, m_opaque_ptr);
+ log->Printf ("SBBroadcaster::SBBroadcaster (broadcaster=%p, bool owns=%i) => SBBroadcaster(%p)",
+ static_cast<void*>(broadcaster), owns,
+ static_cast<void*>(m_opaque_ptr));
}
SBBroadcaster::SBBroadcaster (const SBBroadcaster &rhs) :
@@ -75,7 +76,8 @@ SBBroadcaster::BroadcastEventByType (uint32_t event_type, bool unique)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBroadcaster(%p)::BroadcastEventByType (event_type=0x%8.8x, unique=%i)", m_opaque_ptr, event_type, unique);
+ log->Printf ("SBBroadcaster(%p)::BroadcastEventByType (event_type=0x%8.8x, unique=%i)",
+ static_cast<void*>(m_opaque_ptr), event_type, unique);
if (m_opaque_ptr == NULL)
return;
@@ -92,7 +94,9 @@ SBBroadcaster::BroadcastEvent (const SBEvent &event, bool unique)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBroadcaster(%p)::BroadcastEventByType (SBEvent(%p), unique=%i)", m_opaque_ptr, event.get(), unique);
+ log->Printf ("SBBroadcaster(%p)::BroadcastEventByType (SBEvent(%p), unique=%i)",
+ static_cast<void*>(m_opaque_ptr),
+ static_cast<void*>(event.get()), unique);
if (m_opaque_ptr == NULL)
return;
@@ -109,7 +113,9 @@ SBBroadcaster::AddInitialEventsToListener (const SBListener &listener, uint32_t
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBBroadcaster(%p)::AddInitialEventsToListener (SBListener(%p), event_mask=0x%8.8x)", m_opaque_ptr, listener.get(), requested_events);
+ log->Printf ("SBBroadcaster(%p)::AddInitialEventsToListener (SBListener(%p), event_mask=0x%8.8x)",
+ static_cast<void*>(m_opaque_ptr),
+ static_cast<void*>(listener.get()), requested_events);
if (m_opaque_ptr)
m_opaque_ptr->AddInitialEventsToListener (listener.get(), requested_events);
}
diff --git a/source/API/SBCommandInterpreter.cpp b/source/API/SBCommandInterpreter.cpp
index f1faa13ba981..e1adea795b08 100644
--- a/source/API/SBCommandInterpreter.cpp
+++ b/source/API/SBCommandInterpreter.cpp
@@ -65,7 +65,9 @@ SBCommandInterpreter::SBCommandInterpreter (CommandInterpreter *interpreter) :
if (log)
log->Printf ("SBCommandInterpreter::SBCommandInterpreter (interpreter=%p)"
- " => SBCommandInterpreter(%p)", interpreter, m_opaque_ptr);
+ " => SBCommandInterpreter(%p)",
+ static_cast<void*>(interpreter),
+ static_cast<void*>(m_opaque_ptr));
}
SBCommandInterpreter::SBCommandInterpreter(const SBCommandInterpreter &rhs) :
@@ -129,12 +131,14 @@ SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnOb
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBCommandInterpreter(%p)::HandleCommand (command=\"%s\", SBCommandReturnObject(%p), add_to_history=%i)",
- m_opaque_ptr, command_line, result.get(), add_to_history);
+ log->Printf ("SBCommandInterpreter(%p)::HandleCommand (command=\"%s\", SBCommandReturnObject(%p), add_to_history=%i)",
+ static_cast<void*>(m_opaque_ptr), command_line,
+ static_cast<void*>(result.get()), add_to_history);
result.Clear();
if (command_line && m_opaque_ptr)
{
+ result.ref().SetInteractive(false);
m_opaque_ptr->HandleCommand (command_line, add_to_history ? eLazyBoolYes : eLazyBoolNo, result.ref());
}
else
@@ -150,7 +154,9 @@ SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnOb
SBStream sstr;
result.GetDescription (sstr);
log->Printf ("SBCommandInterpreter(%p)::HandleCommand (command=\"%s\", SBCommandReturnObject(%p): %s, add_to_history=%i) => %i",
- m_opaque_ptr, command_line, result.get(), sstr.GetData(), add_to_history, result.GetStatus());
+ static_cast<void*>(m_opaque_ptr), command_line,
+ static_cast<void*>(result.get()), sstr.GetData(),
+ add_to_history, result.GetStatus());
}
return result.GetStatus();
@@ -166,23 +172,27 @@ SBCommandInterpreter::HandleCompletion (const char *current_line,
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
int num_completions = 0;
-
+
// Sanity check the arguments that are passed in:
// cursor & last_char have to be within the current_line.
if (current_line == NULL || cursor == NULL || last_char == NULL)
return 0;
-
+
if (cursor < current_line || last_char < current_line)
return 0;
-
+
size_t current_line_size = strlen (current_line);
- if (cursor - current_line > current_line_size || last_char - current_line > current_line_size)
+ if (cursor - current_line > static_cast<ptrdiff_t>(current_line_size) ||
+ last_char - current_line > static_cast<ptrdiff_t>(current_line_size))
return 0;
-
+
if (log)
log->Printf ("SBCommandInterpreter(%p)::HandleCompletion (current_line=\"%s\", cursor at: %" PRId64 ", last char at: %" PRId64 ", match_start_point: %d, max_return_elements: %d)",
- m_opaque_ptr, current_line, (uint64_t) (cursor - current_line), (uint64_t) (last_char - current_line), match_start_point, max_return_elements);
-
+ static_cast<void*>(m_opaque_ptr), current_line,
+ static_cast<uint64_t>(cursor - current_line),
+ static_cast<uint64_t>(last_char - current_line),
+ match_start_point, max_return_elements);
+
if (m_opaque_ptr)
{
lldb_private::StringList lldb_matches;
@@ -193,8 +203,9 @@ SBCommandInterpreter::HandleCompletion (const char *current_line,
matches.AppendList (temp_list);
}
if (log)
- log->Printf ("SBCommandInterpreter(%p)::HandleCompletion - Found %d completions.", m_opaque_ptr, num_completions);
-
+ log->Printf ("SBCommandInterpreter(%p)::HandleCompletion - Found %d completions.",
+ static_cast<void*>(m_opaque_ptr), num_completions);
+
return num_completions;
}
@@ -253,9 +264,9 @@ SBCommandInterpreter::GetProcess ()
if (log)
log->Printf ("SBCommandInterpreter(%p)::GetProcess () => SBProcess(%p)",
- m_opaque_ptr, process_sp.get());
+ static_cast<void*>(m_opaque_ptr),
+ static_cast<void*>(process_sp.get()));
-
return sb_process;
}
@@ -266,12 +277,12 @@ SBCommandInterpreter::GetDebugger ()
if (m_opaque_ptr)
sb_debugger.reset(m_opaque_ptr->GetDebugger().shared_from_this());
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
if (log)
log->Printf ("SBCommandInterpreter(%p)::GetDebugger () => SBDebugger(%p)",
- m_opaque_ptr, sb_debugger.get());
-
-
+ static_cast<void*>(m_opaque_ptr),
+ static_cast<void*>(sb_debugger.get()));
+
return sb_debugger;
}
@@ -315,8 +326,8 @@ SBCommandInterpreter::SourceInitFileInHomeDirectory (SBCommandReturnObject &resu
if (log)
log->Printf ("SBCommandInterpreter(%p)::SourceInitFileInHomeDirectory (&SBCommandReturnObject(%p))",
- m_opaque_ptr, result.get());
-
+ static_cast<void*>(m_opaque_ptr),
+ static_cast<void*>(result.get()));
}
void
@@ -340,7 +351,8 @@ SBCommandInterpreter::SourceInitFileInCurrentWorkingDirectory (SBCommandReturnOb
if (log)
log->Printf ("SBCommandInterpreter(%p)::SourceInitFileInCurrentWorkingDirectory (&SBCommandReturnObject(%p))",
- m_opaque_ptr, result.get());
+ static_cast<void*>(m_opaque_ptr),
+ static_cast<void*>(result.get()));
}
SBBroadcaster
@@ -352,7 +364,7 @@ SBCommandInterpreter::GetBroadcaster ()
if (log)
log->Printf ("SBCommandInterpreter(%p)::GetBroadcaster() => SBBroadcaster(%p)",
- m_opaque_ptr, broadcaster.get());
+ static_cast<void*>(m_opaque_ptr), static_cast<void*>(broadcaster.get()));
return broadcaster;
}
diff --git a/source/API/SBCommandReturnObject.cpp b/source/API/SBCommandReturnObject.cpp
index 83d65637d3f2..1ae2df76c979 100644
--- a/source/API/SBCommandReturnObject.cpp
+++ b/source/API/SBCommandReturnObject.cpp
@@ -75,14 +75,16 @@ SBCommandReturnObject::GetOutput ()
if (m_opaque_ap.get())
{
if (log)
- log->Printf ("SBCommandReturnObject(%p)::GetOutput () => \"%s\"", m_opaque_ap.get(),
+ log->Printf ("SBCommandReturnObject(%p)::GetOutput () => \"%s\"",
+ static_cast<void*>(m_opaque_ap.get()),
m_opaque_ap->GetOutputData());
return m_opaque_ap->GetOutputData();
}
if (log)
- log->Printf ("SBCommandReturnObject(%p)::GetOutput () => NULL", m_opaque_ap.get());
+ log->Printf ("SBCommandReturnObject(%p)::GetOutput () => NULL",
+ static_cast<void*>(m_opaque_ap.get()));
return NULL;
}
@@ -95,14 +97,16 @@ SBCommandReturnObject::GetError ()
if (m_opaque_ap.get())
{
if (log)
- log->Printf ("SBCommandReturnObject(%p)::GetError () => \"%s\"", m_opaque_ap.get(),
+ log->Printf ("SBCommandReturnObject(%p)::GetError () => \"%s\"",
+ static_cast<void*>(m_opaque_ap.get()),
m_opaque_ap->GetErrorData());
return m_opaque_ap->GetErrorData();
}
-
+
if (log)
- log->Printf ("SBCommandReturnObject(%p)::GetError () => NULL", m_opaque_ap.get());
+ log->Printf ("SBCommandReturnObject(%p)::GetError () => NULL",
+ static_cast<void*>(m_opaque_ap.get()));
return NULL;
}
diff --git a/source/API/SBCommunication.cpp b/source/API/SBCommunication.cpp
index 10feae5d4ebb..df0b864fad94 100644
--- a/source/API/SBCommunication.cpp
+++ b/source/API/SBCommunication.cpp
@@ -32,7 +32,8 @@ SBCommunication::SBCommunication(const char * broadcaster_name) :
if (log)
log->Printf ("SBCommunication::SBCommunication (broadcaster_name=\"%s\") => "
- "SBCommunication(%p)", broadcaster_name, m_opaque);
+ "SBCommunication(%p)", broadcaster_name,
+ static_cast<void*>(m_opaque));
}
SBCommunication::~SBCommunication()
@@ -97,8 +98,9 @@ SBCommunication::AdoptFileDesriptor (int fd, bool owns_fd)
}
if (log)
- log->Printf ("SBCommunication(%p)::AdoptFileDescriptor (fd=%d, ownd_fd=%i) => %s",
- m_opaque, fd, owns_fd, Communication::ConnectionStatusAsCString (status));
+ log->Printf ("SBCommunication(%p)::AdoptFileDescriptor (fd=%d, ownd_fd=%i) => %s",
+ static_cast<void*>(m_opaque), fd, owns_fd,
+ Communication::ConnectionStatusAsCString (status));
return status;
}
@@ -114,7 +116,8 @@ SBCommunication::Disconnect ()
status = m_opaque->Disconnect ();
if (log)
- log->Printf ("SBCommunication(%p)::Disconnect () => %s", m_opaque,
+ log->Printf ("SBCommunication(%p)::Disconnect () => %s",
+ static_cast<void*>(m_opaque),
Communication::ConnectionStatusAsCString (status));
return status;
@@ -129,7 +132,8 @@ SBCommunication::IsConnected () const
result = m_opaque->IsConnected ();
if (log)
- log->Printf ("SBCommunication(%p)::IsConnected () => %i", m_opaque, result);
+ log->Printf ("SBCommunication(%p)::IsConnected () => %i",
+ static_cast<void*>(m_opaque), result);
return false;
}
@@ -140,10 +144,8 @@ SBCommunication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, Connect
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
log->Printf ("SBCommunication(%p)::Read (dst=%p, dst_len=%" PRIu64 ", timeout_usec=%u, &status)...",
- m_opaque,
- dst,
- (uint64_t)dst_len,
- timeout_usec);
+ static_cast<void*>(m_opaque), static_cast<void*>(dst),
+ static_cast<uint64_t>(dst_len), timeout_usec);
size_t bytes_read = 0;
if (m_opaque)
bytes_read = m_opaque->Read (dst, dst_len, timeout_usec, status, NULL);
@@ -152,12 +154,10 @@ SBCommunication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, Connect
if (log)
log->Printf ("SBCommunication(%p)::Read (dst=%p, dst_len=%" PRIu64 ", timeout_usec=%u, &status=%s) => %" PRIu64,
- m_opaque,
- dst,
- (uint64_t)dst_len,
- timeout_usec,
+ static_cast<void*>(m_opaque), static_cast<void*>(dst),
+ static_cast<uint64_t>(dst_len), timeout_usec,
Communication::ConnectionStatusAsCString (status),
- (uint64_t)bytes_read);
+ static_cast<uint64_t>(bytes_read));
return bytes_read;
}
@@ -174,7 +174,10 @@ SBCommunication::Write (const void *src, size_t src_len, ConnectionStatus &statu
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
log->Printf ("SBCommunication(%p)::Write (src=%p, src_len=%" PRIu64 ", &status=%s) => %" PRIu64,
- m_opaque, src, (uint64_t)src_len, Communication::ConnectionStatusAsCString (status), (uint64_t)bytes_written);
+ static_cast<void*>(m_opaque), static_cast<const void*>(src),
+ static_cast<uint64_t>(src_len),
+ Communication::ConnectionStatusAsCString (status),
+ static_cast<uint64_t>(bytes_written));
return 0;
}
@@ -189,7 +192,8 @@ SBCommunication::ReadThreadStart ()
success = m_opaque->StartReadThread ();
if (log)
- log->Printf ("SBCommunication(%p)::ReadThreadStart () => %i", m_opaque, success);
+ log->Printf ("SBCommunication(%p)::ReadThreadStart () => %i",
+ static_cast<void*>(m_opaque), success);
return success;
}
@@ -200,14 +204,16 @@ SBCommunication::ReadThreadStop ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBCommunication(%p)::ReadThreadStop ()...", m_opaque);
+ log->Printf ("SBCommunication(%p)::ReadThreadStop ()...",
+ static_cast<void*>(m_opaque));
bool success = false;
if (m_opaque)
success = m_opaque->StopReadThread ();
if (log)
- log->Printf ("SBCommunication(%p)::ReadThreadStop () => %i", m_opaque, success);
+ log->Printf ("SBCommunication(%p)::ReadThreadStop () => %i",
+ static_cast<void*>(m_opaque), success);
return success;
}
@@ -220,7 +226,8 @@ SBCommunication::ReadThreadIsRunning ()
result = m_opaque->ReadThreadIsRunning ();
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBCommunication(%p)::ReadThreadIsRunning () => %i", m_opaque, result);
+ log->Printf ("SBCommunication(%p)::ReadThreadIsRunning () => %i",
+ static_cast<void*>(m_opaque), result);
return result;
}
@@ -242,7 +249,9 @@ SBCommunication::SetReadThreadBytesReceivedCallback
if (log)
log->Printf ("SBCommunication(%p)::SetReadThreadBytesReceivedCallback (callback=%p, baton=%p) => %i",
- m_opaque, callback, callback_baton, result);
+ static_cast<void*>(m_opaque),
+ reinterpret_cast<void*>(reinterpret_cast<intptr_t>(callback)),
+ static_cast<void*>(callback_baton), result);
return result;
}
@@ -256,7 +265,8 @@ SBCommunication::GetBroadcaster ()
if (log)
log->Printf ("SBCommunication(%p)::GetBroadcaster () => SBBroadcaster (%p)",
- m_opaque, broadcaster.get());
+ static_cast<void*>(m_opaque),
+ static_cast<void*>(broadcaster.get()));
return broadcaster;
}
diff --git a/source/API/SBCompileUnit.cpp b/source/API/SBCompileUnit.cpp
index 9f7487746a85..03c25710a9e4 100644
--- a/source/API/SBCompileUnit.cpp
+++ b/source/API/SBCompileUnit.cpp
@@ -87,13 +87,14 @@ SBCompileUnit::GetLineEntryAtIndex (uint32_t idx) const
sb_line_entry.SetLineEntry(line_entry);
}
}
-
+
if (log)
{
SBStream sstr;
sb_line_entry.GetDescription (sstr);
- log->Printf ("SBCompileUnit(%p)::GetLineEntryAtIndex (idx=%u) => SBLineEntry(%p): '%s'",
- m_opaque_ptr, idx, sb_line_entry.get(), sstr.GetData());
+ log->Printf ("SBCompileUnit(%p)::GetLineEntryAtIndex (idx=%u) => SBLineEntry(%p): '%s'",
+ static_cast<void*>(m_opaque_ptr), idx,
+ static_cast<void*>(sb_line_entry.get()), sstr.GetData());
}
return sb_line_entry;
@@ -120,7 +121,6 @@ SBCompileUnit::FindLineEntryIndex (uint32_t start_idx, uint32_t line, SBFileSpec
else
file_spec = *m_opaque_ptr;
-
index = m_opaque_ptr->FindLineEntry (start_idx,
line,
inline_file_spec ? inline_file_spec->get() : NULL,
@@ -133,13 +133,20 @@ SBCompileUnit::FindLineEntryIndex (uint32_t start_idx, uint32_t line, SBFileSpec
SBStream sstr;
if (index == UINT32_MAX)
{
- log->Printf ("SBCompileUnit(%p)::FindLineEntryIndex (start_idx=%u, line=%u, SBFileSpec(%p)) => NOT FOUND",
- m_opaque_ptr, start_idx, line, inline_file_spec ? inline_file_spec->get() : NULL);
+ log->Printf ("SBCompileUnit(%p)::FindLineEntryIndex (start_idx=%u, line=%u, SBFileSpec(%p)) => NOT FOUND",
+ static_cast<void*>(m_opaque_ptr), start_idx, line,
+ inline_file_spec
+ ? static_cast<const void*>(inline_file_spec->get())
+ : NULL);
}
else
{
- log->Printf ("SBCompileUnit(%p)::FindLineEntryIndex (start_idx=%u, line=%u, SBFileSpec(%p)) => %u",
- m_opaque_ptr, start_idx, line, inline_file_spec ? inline_file_spec->get() : NULL, index);
+ log->Printf ("SBCompileUnit(%p)::FindLineEntryIndex (start_idx=%u, line=%u, SBFileSpec(%p)) => %u",
+ static_cast<void*>(m_opaque_ptr), start_idx, line,
+ inline_file_spec
+ ? static_cast<const void*>(inline_file_spec->get())
+ : NULL,
+ index);
}
}
@@ -196,13 +203,15 @@ SBCompileUnit::GetSupportFileAtIndex (uint32_t idx) const
FileSpec file_spec = support_files.GetFileSpecAtIndex(idx);
sb_file_spec.SetFileSpec(file_spec);
}
-
+
if (log)
{
SBStream sstr;
sb_file_spec.GetDescription (sstr);
- log->Printf ("SBCompileUnit(%p)::GetGetFileSpecAtIndex (idx=%u) => SBFileSpec(%p): '%s'",
- m_opaque_ptr, idx, sb_file_spec.get(), sstr.GetData());
+ log->Printf ("SBCompileUnit(%p)::GetGetFileSpecAtIndex (idx=%u) => SBFileSpec(%p): '%s'",
+ static_cast<void*>(m_opaque_ptr), idx,
+ static_cast<const void*>(sb_file_spec.get()),
+ sstr.GetData());
}
return sb_file_spec;
diff --git a/source/API/SBData.cpp b/source/API/SBData.cpp
index 06dcfc12af41..a58585295a21 100644
--- a/source/API/SBData.cpp
+++ b/source/API/SBData.cpp
@@ -7,6 +7,8 @@
//
//===----------------------------------------------------------------------===//
+#include <inttypes.h> // PRIu64
+
#include "lldb/API/SBData.h"
#include "lldb/API/SBError.h"
#include "lldb/API/SBStream.h"
@@ -122,7 +124,7 @@ SBData::GetByteSize ()
value = m_opaque_sp->GetByteSize();
if (log)
log->Printf ("SBData::GetByteSize () => "
- "(%zu)", value);
+ "( %" PRIu64 " )", (uint64_t)value);
return value;
}
@@ -167,8 +169,8 @@ SBData::GetFloat (lldb::SBError& error, lldb::offset_t offset)
error.SetErrorString("unable to read data");
}
if (log)
- log->Printf ("SBData::GetFloat (error=%p,offset=%" PRIu64 ") => "
- "(%f)", error.get(), offset, value);
+ log->Printf ("SBData::GetFloat (error=%p,offset=%" PRIu64 ") => (%f)",
+ static_cast<void*>(error.get()), offset, value);
return value;
}
@@ -190,7 +192,7 @@ SBData::GetDouble (lldb::SBError& error, lldb::offset_t offset)
}
if (log)
log->Printf ("SBData::GetDouble (error=%p,offset=%" PRIu64 ") => "
- "(%f)", error.get(), offset, value);
+ "(%f)", static_cast<void*>(error.get()), offset, value);
return value;
}
@@ -212,7 +214,7 @@ SBData::GetLongDouble (lldb::SBError& error, lldb::offset_t offset)
}
if (log)
log->Printf ("SBData::GetLongDouble (error=%p,offset=%" PRIu64 ") => "
- "(%Lf)", error.get(), offset, value);
+ "(%Lf)", static_cast<void*>(error.get()), offset, value);
return value;
}
@@ -234,7 +236,8 @@ SBData::GetAddress (lldb::SBError& error, lldb::offset_t offset)
}
if (log)
log->Printf ("SBData::GetAddress (error=%p,offset=%" PRIu64 ") => "
- "(%p)", error.get(), offset, (void*)value);
+ "(%p)", static_cast<void*>(error.get()), offset,
+ reinterpret_cast<void*>(value));
return value;
}
@@ -256,7 +259,7 @@ SBData::GetUnsignedInt8 (lldb::SBError& error, lldb::offset_t offset)
}
if (log)
log->Printf ("SBData::GetUnsignedInt8 (error=%p,offset=%" PRIu64 ") => "
- "(%c)", error.get(), offset, value);
+ "(%c)", static_cast<void*>(error.get()), offset, value);
return value;
}
@@ -278,7 +281,7 @@ SBData::GetUnsignedInt16 (lldb::SBError& error, lldb::offset_t offset)
}
if (log)
log->Printf ("SBData::GetUnsignedInt16 (error=%p,offset=%" PRIu64 ") => "
- "(%hd)", error.get(), offset, value);
+ "(%hd)", static_cast<void*>(error.get()), offset, value);
return value;
}
@@ -300,7 +303,7 @@ SBData::GetUnsignedInt32 (lldb::SBError& error, lldb::offset_t offset)
}
if (log)
log->Printf ("SBData::GetUnsignedInt32 (error=%p,offset=%" PRIu64 ") => "
- "(%d)", error.get(), offset, value);
+ "(%d)", static_cast<void*>(error.get()), offset, value);
return value;
}
@@ -322,7 +325,8 @@ SBData::GetUnsignedInt64 (lldb::SBError& error, lldb::offset_t offset)
}
if (log)
log->Printf ("SBData::GetUnsignedInt64 (error=%p,offset=%" PRIu64 ") => "
- "(%" PRId64 ")", error.get(), offset, value);
+ "(%" PRId64 ")", static_cast<void*>(error.get()), offset,
+ value);
return value;
}
@@ -344,7 +348,7 @@ SBData::GetSignedInt8 (lldb::SBError& error, lldb::offset_t offset)
}
if (log)
log->Printf ("SBData::GetSignedInt8 (error=%p,offset=%" PRIu64 ") => "
- "(%c)", error.get(), offset, value);
+ "(%c)", static_cast<void*>(error.get()), offset, value);
return value;
}
@@ -366,7 +370,7 @@ SBData::GetSignedInt16 (lldb::SBError& error, lldb::offset_t offset)
}
if (log)
log->Printf ("SBData::GetSignedInt16 (error=%p,offset=%" PRIu64 ") => "
- "(%hd)", error.get(), offset, value);
+ "(%hd)", static_cast<void*>(error.get()), offset, value);
return value;
}
@@ -388,7 +392,7 @@ SBData::GetSignedInt32 (lldb::SBError& error, lldb::offset_t offset)
}
if (log)
log->Printf ("SBData::GetSignedInt32 (error=%p,offset=%" PRIu64 ") => "
- "(%d)", error.get(), offset, value);
+ "(%d)", static_cast<void*>(error.get()), offset, value);
return value;
}
@@ -410,7 +414,8 @@ SBData::GetSignedInt64 (lldb::SBError& error, lldb::offset_t offset)
}
if (log)
log->Printf ("SBData::GetSignedInt64 (error=%p,offset=%" PRIu64 ") => "
- "(%" PRId64 ")", error.get(), offset, value);
+ "(%" PRId64 ")", static_cast<void*>(error.get()), offset,
+ value);
return value;
}
@@ -431,8 +436,9 @@ SBData::GetString (lldb::SBError& error, lldb::offset_t offset)
error.SetErrorString("unable to read data");
}
if (log)
- log->Printf ("SBData::GetString (error=%p,offset=%" PRIu64 ") => "
- "(%p)", error.get(), offset, value);
+ log->Printf ("SBData::GetString (error=%p,offset=%" PRIu64 ") => (%p)",
+ static_cast<void*>(error.get()), offset,
+ static_cast<const void*>(value));
return value;
}
@@ -479,8 +485,10 @@ SBData::ReadRawData (lldb::SBError& error,
error.SetErrorString("unable to read data");
}
if (log)
- log->Printf ("SBData::ReadRawData (error=%p,offset=%" PRIu64 ",buf=%p,size=%zu) => "
- "(%p)", error.get(), offset, buf, size, ok);
+ log->Printf("SBData::ReadRawData (error=%p,offset=%" PRIu64 ",buf=%p,size=%" PRIu64 ") => "
+ "(%p)", static_cast<void*>(error.get()), offset,
+ static_cast<void*>(buf), static_cast<uint64_t>(size),
+ static_cast<void*>(ok));
return ok ? size : 0;
}
@@ -497,8 +505,10 @@ SBData::SetData (lldb::SBError& error,
else
m_opaque_sp->SetData(buf, size, endian);
if (log)
- log->Printf ("SBData::SetData (error=%p,buf=%p,size=%zu,endian=%d,addr_size=%c) => "
- "(%p)", error.get(), buf, size, endian, addr_size, m_opaque_sp.get());
+ log->Printf("SBData::SetData (error=%p,buf=%p,size=%" PRIu64 ",endian=%d,addr_size=%c) => "
+ "(%p)", static_cast<void*>(error.get()),
+ static_cast<const void*>(buf), static_cast<uint64_t>(size),
+ endian, addr_size, static_cast<void*>(m_opaque_sp.get()));
}
bool
@@ -509,8 +519,8 @@ SBData::Append (const SBData& rhs)
if (m_opaque_sp.get() && rhs.m_opaque_sp.get())
value = m_opaque_sp.get()->Append(*rhs.m_opaque_sp);
if (log)
- log->Printf ("SBData::Append (rhs=%p) => "
- "(%s)", rhs.get(), value ? "true" : "false");
+ log->Printf ("SBData::Append (rhs=%p) => (%s)",
+ static_cast<void*>(rhs.get()), value ? "true" : "false");
return value;
}
@@ -614,28 +624,28 @@ bool
SBData::SetDataFromCString (const char* data)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
if (!data)
{
if (log)
- log->Printf ("SBData::SetDataFromCString (data=%p) => "
- "false", data);
+ log->Printf ("SBData::SetDataFromCString (data=%p) => false",
+ static_cast<const void*>(data));
return false;
}
-
+
size_t data_len = strlen(data);
-
+
lldb::DataBufferSP buffer_sp(new DataBufferHeap(data, data_len));
-
+
if (!m_opaque_sp.get())
m_opaque_sp.reset(new DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()));
else
m_opaque_sp->SetData(buffer_sp);
-
+
if (log)
- log->Printf ("SBData::SetDataFromCString (data=%p) => "
- "true", data);
-
+ log->Printf ("SBData::SetDataFromCString (data=%p) => true",
+ static_cast<const void*>(data));
+
return true;
}
@@ -643,28 +653,30 @@ bool
SBData::SetDataFromUInt64Array (uint64_t* array, size_t array_len)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
if (!array || array_len == 0)
{
if (log)
- log->Printf ("SBData::SetDataFromUInt64Array (array=%p, array_len = %zu) => "
- "false", array, array_len);
+ log->Printf("SBData::SetDataFromUInt64Array (array=%p, array_len = %" PRIu64 ") => "
+ "false", static_cast<void*>(array),
+ static_cast<uint64_t>(array_len));
return false;
}
size_t data_len = array_len * sizeof(uint64_t);
-
+
lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
-
+
if (!m_opaque_sp.get())
m_opaque_sp.reset(new DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()));
else
m_opaque_sp->SetData(buffer_sp);
-
+
if (log)
- log->Printf ("SBData::SetDataFromUInt64Array (array=%p, array_len = %zu) => "
- "true", array, array_len);
-
+ log->Printf("SBData::SetDataFromUInt64Array (array=%p, array_len = %" PRIu64 ") => "
+ "true", static_cast<void*>(array),
+ static_cast<uint64_t>(array_len));
+
return true;
}
@@ -672,28 +684,30 @@ bool
SBData::SetDataFromUInt32Array (uint32_t* array, size_t array_len)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
if (!array || array_len == 0)
{
if (log)
- log->Printf ("SBData::SetDataFromUInt32Array (array=%p, array_len = %zu) => "
- "false", array, array_len);
+ log->Printf("SBData::SetDataFromUInt32Array (array=%p, array_len = %" PRIu64 ") => "
+ "false", static_cast<void*>(array),
+ static_cast<uint64_t>(array_len));
return false;
}
-
+
size_t data_len = array_len * sizeof(uint32_t);
-
+
lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
-
+
if (!m_opaque_sp.get())
m_opaque_sp.reset(new DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()));
else
m_opaque_sp->SetData(buffer_sp);
-
+
if (log)
- log->Printf ("SBData::SetDataFromUInt32Array (array=%p, array_len = %zu) => "
- "true", array, array_len);
-
+ log->Printf("SBData::SetDataFromUInt32Array (array=%p, array_len = %" PRIu64 ") => "
+ "true", static_cast<void*>(array),
+ static_cast<uint64_t>(array_len));
+
return true;
}
@@ -701,28 +715,30 @@ bool
SBData::SetDataFromSInt64Array (int64_t* array, size_t array_len)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
if (!array || array_len == 0)
{
if (log)
- log->Printf ("SBData::SetDataFromSInt64Array (array=%p, array_len = %zu) => "
- "false", array, array_len);
+ log->Printf("SBData::SetDataFromSInt64Array (array=%p, array_len = %" PRIu64 ") => "
+ "false", static_cast<void*>(array),
+ static_cast<uint64_t>(array_len));
return false;
}
-
+
size_t data_len = array_len * sizeof(int64_t);
-
+
lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
-
+
if (!m_opaque_sp.get())
m_opaque_sp.reset(new DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()));
else
m_opaque_sp->SetData(buffer_sp);
-
+
if (log)
- log->Printf ("SBData::SetDataFromSInt64Array (array=%p, array_len = %zu) => "
- "true", array, array_len);
-
+ log->Printf("SBData::SetDataFromSInt64Array (array=%p, array_len = %" PRIu64 ") => "
+ "true", static_cast<void*>(array),
+ static_cast<uint64_t>(array_len));
+
return true;
}
@@ -730,28 +746,30 @@ bool
SBData::SetDataFromSInt32Array (int32_t* array, size_t array_len)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
if (!array || array_len == 0)
{
if (log)
- log->Printf ("SBData::SetDataFromSInt32Array (array=%p, array_len = %zu) => "
- "false", array, array_len);
+ log->Printf("SBData::SetDataFromSInt32Array (array=%p, array_len = %" PRIu64 ") => "
+ "false", static_cast<void*>(array),
+ static_cast<uint64_t>(array_len));
return false;
}
-
+
size_t data_len = array_len * sizeof(int32_t);
-
+
lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
-
+
if (!m_opaque_sp.get())
m_opaque_sp.reset(new DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()));
else
m_opaque_sp->SetData(buffer_sp);
-
+
if (log)
- log->Printf ("SBData::SetDataFromSInt32Array (array=%p, array_len = %zu) => "
- "true", array, array_len);
-
+ log->Printf("SBData::SetDataFromSInt32Array (array=%p, array_len = %" PRIu64 ") => "
+ "true", static_cast<void*>(array),
+ static_cast<uint64_t>(array_len));
+
return true;
}
@@ -759,27 +777,29 @@ bool
SBData::SetDataFromDoubleArray (double* array, size_t array_len)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
if (!array || array_len == 0)
{
if (log)
- log->Printf ("SBData::SetDataFromDoubleArray (array=%p, array_len = %zu) => "
- "false", array, array_len);
+ log->Printf("SBData::SetDataFromDoubleArray (array=%p, array_len = %" PRIu64 ") => "
+ "false", static_cast<void*>(array),
+ static_cast<uint64_t>(array_len));
return false;
}
-
+
size_t data_len = array_len * sizeof(double);
-
+
lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
-
+
if (!m_opaque_sp.get())
m_opaque_sp.reset(new DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()));
else
m_opaque_sp->SetData(buffer_sp);
-
+
if (log)
- log->Printf ("SBData::SetDataFromDoubleArray (array=%p, array_len = %zu) => "
- "true", array, array_len);
-
+ log->Printf("SBData::SetDataFromDoubleArray (array=%p, array_len = %" PRIu64 ") => "
+ "true", static_cast<void*>(array),
+ static_cast<uint64_t>(array_len));
+
return true;
}
diff --git a/source/API/SBDebugger.cpp b/source/API/SBDebugger.cpp
index 8d6887a6c280..dae567525a4a 100644
--- a/source/API/SBDebugger.cpp
+++ b/source/API/SBDebugger.cpp
@@ -38,13 +38,14 @@
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/DataFormatters/DataVisualization.h"
-#include "lldb/Host/DynamicLibrary.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/DynamicLibrary.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -72,22 +73,22 @@ SBInputReader::IsActive() const
return false;
}
-static lldb::DynamicLibrarySP
+static llvm::sys::DynamicLibrary
LoadPlugin (const lldb::DebuggerSP &debugger_sp, const FileSpec& spec, Error& error)
{
- lldb::DynamicLibrarySP dynlib_sp(new lldb_private::DynamicLibrary(spec));
- if (dynlib_sp && dynlib_sp->IsValid())
+ llvm::sys::DynamicLibrary dynlib = llvm::sys::DynamicLibrary::getPermanentLibrary(spec.GetPath().c_str());
+ if (dynlib.isValid())
{
typedef bool (*LLDBCommandPluginInit) (lldb::SBDebugger& debugger);
lldb::SBDebugger debugger_sb(debugger_sp);
// This calls the bool lldb::PluginInitialize(lldb::SBDebugger debugger) function.
// TODO: mangle this differently for your system - on OSX, the first underscore needs to be removed and the second one stays
- LLDBCommandPluginInit init_func = dynlib_sp->GetSymbol<LLDBCommandPluginInit>("_ZN4lldb16PluginInitializeENS_10SBDebuggerE");
+ LLDBCommandPluginInit init_func = (LLDBCommandPluginInit)dynlib.getAddressOfSymbol("_ZN4lldb16PluginInitializeENS_10SBDebuggerE");
if (init_func)
{
if (init_func(debugger_sb))
- return dynlib_sp;
+ return dynlib;
else
error.SetErrorString("plug-in refused to load (lldb::PluginInitialize(lldb::SBDebugger) returned false)");
}
@@ -103,7 +104,7 @@ LoadPlugin (const lldb::DebuggerSP &debugger_sp, const FileSpec& spec, Error& er
else
error.SetErrorString("no such file");
}
- return lldb::DynamicLibrarySP();
+ return llvm::sys::DynamicLibrary();
}
void
@@ -131,8 +132,9 @@ SBDebugger::Clear ()
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBDebugger(%p)::Clear ()", m_opaque_sp.get());
-
+ log->Printf ("SBDebugger(%p)::Clear ()",
+ static_cast<void*>(m_opaque_sp.get()));
+
if (m_opaque_sp)
m_opaque_sp->ClearIOHandlers ();
@@ -158,13 +160,24 @@ SBDebugger::Create(bool source_init_files, lldb::LogOutputCallback callback, voi
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
SBDebugger debugger;
+
+ // Currently we have issues if this function is called simultaneously on two different
+ // threads. The issues mainly revolve around the fact that the lldb_private::FormatManager
+ // uses global collections and having two threads parsing the .lldbinit files can cause
+ // mayhem. So to get around this for now we need to use a mutex to prevent bad things
+ // from happening.
+ static Mutex g_mutex(Mutex::eMutexTypeRecursive);
+ Mutex::Locker locker(g_mutex);
+
debugger.reset(Debugger::CreateInstance(callback, baton));
if (log)
{
SBStream sstr;
debugger.GetDescription (sstr);
- log->Printf ("SBDebugger::Create () => SBDebugger(%p): %s", debugger.m_opaque_sp.get(), sstr.GetData());
+ log->Printf ("SBDebugger::Create () => SBDebugger(%p): %s",
+ static_cast<void*>(debugger.m_opaque_sp.get()),
+ sstr.GetData());
}
SBCommandInterpreter interp = debugger.GetCommandInterpreter();
@@ -187,16 +200,18 @@ void
SBDebugger::Destroy (SBDebugger &debugger)
{
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
if (log)
{
SBStream sstr;
debugger.GetDescription (sstr);
- log->Printf ("SBDebugger::Destroy () => SBDebugger(%p): %s", debugger.m_opaque_sp.get(), sstr.GetData());
+ log->Printf ("SBDebugger::Destroy () => SBDebugger(%p): %s",
+ static_cast<void*>(debugger.m_opaque_sp.get()),
+ sstr.GetData());
}
-
+
Debugger::Destroy (debugger.m_opaque_sp);
-
+
if (debugger.m_opaque_sp.get() != NULL)
debugger.m_opaque_sp.reset();
}
@@ -293,8 +308,9 @@ SBDebugger::SetInputFileHandle (FILE *fh, bool transfer_ownership)
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBDebugger(%p)::SetInputFileHandle (fh=%p, transfer_ownership=%i)", m_opaque_sp.get(),
- fh, transfer_ownership);
+ log->Printf ("SBDebugger(%p)::SetInputFileHandle (fh=%p, transfer_ownership=%i)",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(fh), transfer_ownership);
if (m_opaque_sp)
m_opaque_sp->SetInputFileHandle (fh, transfer_ownership);
@@ -307,8 +323,9 @@ SBDebugger::SetOutputFileHandle (FILE *fh, bool transfer_ownership)
if (log)
- log->Printf ("SBDebugger(%p)::SetOutputFileHandle (fh=%p, transfer_ownership=%i)", m_opaque_sp.get(),
- fh, transfer_ownership);
+ log->Printf ("SBDebugger(%p)::SetOutputFileHandle (fh=%p, transfer_ownership=%i)",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(fh), transfer_ownership);
if (m_opaque_sp)
m_opaque_sp->SetOutputFileHandle (fh, transfer_ownership);
@@ -321,8 +338,9 @@ SBDebugger::SetErrorFileHandle (FILE *fh, bool transfer_ownership)
if (log)
- log->Printf ("SBDebugger(%p)::SetErrorFileHandle (fh=%p, transfer_ownership=%i)", m_opaque_sp.get(),
- fh, transfer_ownership);
+ log->Printf ("SBDebugger(%p)::SetErrorFileHandle (fh=%p, transfer_ownership=%i)",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(fh), transfer_ownership);
if (m_opaque_sp)
m_opaque_sp->SetErrorFileHandle (fh, transfer_ownership);
@@ -389,8 +407,9 @@ SBDebugger::GetCommandInterpreter ()
sb_interpreter.reset (&m_opaque_sp->GetCommandInterpreter());
if (log)
- log->Printf ("SBDebugger(%p)::GetCommandInterpreter () => SBCommandInterpreter(%p)",
- m_opaque_sp.get(), sb_interpreter.get());
+ log->Printf ("SBDebugger(%p)::GetCommandInterpreter () => SBCommandInterpreter(%p)",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(sb_interpreter.get()));
return sb_interpreter;
}
@@ -443,8 +462,9 @@ SBDebugger::GetListener ()
sb_listener.reset(&m_opaque_sp->GetListener(), false);
if (log)
- log->Printf ("SBDebugger(%p)::GetListener () => SBListener(%p)", m_opaque_sp.get(),
- sb_listener.get());
+ log->Printf ("SBDebugger(%p)::GetListener () => SBListener(%p)",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(sb_listener.get()));
return sb_listener;
}
@@ -601,14 +621,14 @@ SBDebugger::CreateTarget (const char *filename,
sb_error.Clear();
OptionGroupPlatform platform_options (false);
platform_options.SetPlatformName (platform_name);
-
+
sb_error.ref() = m_opaque_sp->GetTargetList().CreateTarget (*m_opaque_sp,
filename,
target_triple,
add_dependent_modules,
&platform_options,
target_sp);
-
+
if (sb_error.Success())
sb_target.SetSP (target_sp);
}
@@ -616,20 +636,14 @@ SBDebugger::CreateTarget (const char *filename,
{
sb_error.SetErrorString("invalid target");
}
-
+
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- {
- log->Printf ("SBDebugger(%p)::CreateTarget (filename=\"%s\", triple=%s, platform_name=%s, add_dependent_modules=%u, error=%s) => SBTarget(%p)",
- m_opaque_sp.get(),
- filename,
- target_triple,
- platform_name,
- add_dependent_modules,
- sb_error.GetCString(),
- target_sp.get());
- }
-
+ log->Printf ("SBDebugger(%p)::CreateTarget (filename=\"%s\", triple=%s, platform_name=%s, add_dependent_modules=%u, error=%s) => SBTarget(%p)",
+ static_cast<void*>(m_opaque_sp.get()), filename,
+ target_triple, platform_name, add_dependent_modules,
+ sb_error.GetCString(), static_cast<void*>(target_sp.get()));
+
return sb_target;
}
@@ -650,13 +664,12 @@ SBDebugger::CreateTargetWithFileAndTargetTriple (const char *filename,
target_sp));
sb_target.SetSP (target_sp);
}
-
+
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- {
- log->Printf ("SBDebugger(%p)::CreateTargetWithFileAndTargetTriple (filename=\"%s\", triple=%s) => SBTarget(%p)",
- m_opaque_sp.get(), filename, target_triple, target_sp.get());
- }
+ log->Printf ("SBDebugger(%p)::CreateTargetWithFileAndTargetTriple (filename=\"%s\", triple=%s) => SBTarget(%p)",
+ static_cast<void*>(m_opaque_sp.get()), filename,
+ target_triple, static_cast<void*>(target_sp.get()));
return sb_target;
}
@@ -688,10 +701,9 @@ SBDebugger::CreateTargetWithFileAndArch (const char *filename, const char *arch_
}
if (log)
- {
- log->Printf ("SBDebugger(%p)::CreateTargetWithFileAndArch (filename=\"%s\", arch=%s) => SBTarget(%p)",
- m_opaque_sp.get(), filename, arch_cstr, target_sp.get());
- }
+ log->Printf ("SBDebugger(%p)::CreateTargetWithFileAndArch (filename=\"%s\", arch=%s) => SBTarget(%p)",
+ static_cast<void*>(m_opaque_sp.get()), filename, arch_cstr,
+ static_cast<void*>(target_sp.get()));
return sb_target;
}
@@ -723,10 +735,9 @@ SBDebugger::CreateTarget (const char *filename)
}
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- {
- log->Printf ("SBDebugger(%p)::CreateTarget (filename=\"%s\") => SBTarget(%p)",
- m_opaque_sp.get(), filename, target_sp.get());
- }
+ log->Printf ("SBDebugger(%p)::CreateTarget (filename=\"%s\") => SBTarget(%p)",
+ static_cast<void*>(m_opaque_sp.get()), filename,
+ static_cast<void*>(target_sp.get()));
return sb_target;
}
@@ -750,9 +761,9 @@ SBDebugger::DeleteTarget (lldb::SBTarget &target)
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- {
- log->Printf ("SBDebugger(%p)::DeleteTarget (SBTarget(%p)) => %i", m_opaque_sp.get(), target.m_opaque_sp.get(), result);
- }
+ log->Printf ("SBDebugger(%p)::DeleteTarget (SBTarget(%p)) => %i",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(target.m_opaque_sp.get()), result);
return result;
}
@@ -850,8 +861,9 @@ SBDebugger::GetSelectedTarget ()
{
SBStream sstr;
sb_target.GetDescription (sstr, eDescriptionLevelBrief);
- log->Printf ("SBDebugger(%p)::GetSelectedTarget () => SBTarget(%p): %s", m_opaque_sp.get(),
- target_sp.get(), sstr.GetData());
+ log->Printf ("SBDebugger(%p)::GetSelectedTarget () => SBTarget(%p): %s",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(target_sp.get()), sstr.GetData());
}
return sb_target;
@@ -871,8 +883,9 @@ SBDebugger::SetSelectedTarget (SBTarget &sb_target)
{
SBStream sstr;
sb_target.GetDescription (sstr, eDescriptionLevelBrief);
- log->Printf ("SBDebugger(%p)::SetSelectedTarget () => SBTarget(%p): %s", m_opaque_sp.get(),
- target_sp.get(), sstr.GetData());
+ log->Printf ("SBDebugger(%p)::SetSelectedTarget () => SBTarget(%p): %s",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(target_sp.get()), sstr.GetData());
}
}
@@ -888,10 +901,10 @@ SBDebugger::GetSelectedPlatform()
sb_platform.SetSP(debugger_sp->GetPlatformList().GetSelectedPlatform());
}
if (log)
- {
- log->Printf ("SBDebugger(%p)::GetSelectedPlatform () => SBPlatform(%p): %s", m_opaque_sp.get(),
- sb_platform.GetSP().get(), sb_platform.GetName());
- }
+ log->Printf ("SBDebugger(%p)::GetSelectedPlatform () => SBPlatform(%p): %s",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(sb_platform.GetSP().get()),
+ sb_platform.GetName());
return sb_platform;
}
@@ -899,17 +912,18 @@ void
SBDebugger::SetSelectedPlatform(SBPlatform &sb_platform)
{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
DebuggerSP debugger_sp(m_opaque_sp);
if (debugger_sp)
{
debugger_sp->GetPlatformList().SetSelectedPlatform(sb_platform.GetSP());
}
+
if (log)
- {
- log->Printf ("SBDebugger(%p)::SetSelectedPlatform (SBPlatform(%p) %s)", m_opaque_sp.get(),
- sb_platform.GetSP().get(), sb_platform.GetName());
- }
+ log->Printf ("SBDebugger(%p)::SetSelectedPlatform (SBPlatform(%p) %s)",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(sb_platform.GetSP().get()),
+ sb_platform.GetName());
}
void
@@ -1077,9 +1091,10 @@ const char *
SBDebugger::GetPrompt() const
{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
if (log)
- log->Printf ("SBDebugger(%p)::GetPrompt () => \"%s\"", m_opaque_sp.get(),
+ log->Printf ("SBDebugger(%p)::GetPrompt () => \"%s\"",
+ static_cast<void*>(m_opaque_sp.get()),
(m_opaque_sp ? m_opaque_sp->GetPrompt() : ""));
if (m_opaque_sp)
diff --git a/source/API/SBDeclaration.cpp b/source/API/SBDeclaration.cpp
index fc90156e75ad..8aea675afeba 100644
--- a/source/API/SBDeclaration.cpp
+++ b/source/API/SBDeclaration.cpp
@@ -74,19 +74,21 @@ SBFileSpec
SBDeclaration::GetFileSpec () const
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
SBFileSpec sb_file_spec;
if (m_opaque_ap.get() && m_opaque_ap->GetFile())
sb_file_spec.SetFileSpec(m_opaque_ap->GetFile());
-
+
if (log)
{
SBStream sstr;
sb_file_spec.GetDescription (sstr);
- log->Printf ("SBLineEntry(%p)::GetFileSpec () => SBFileSpec(%p): %s", m_opaque_ap.get(),
- sb_file_spec.get(), sstr.GetData());
+ log->Printf ("SBLineEntry(%p)::GetFileSpec () => SBFileSpec(%p): %s",
+ static_cast<void*>(m_opaque_ap.get()),
+ static_cast<const void*>(sb_file_spec.get()),
+ sstr.GetData());
}
-
+
return sb_file_spec;
}
@@ -94,14 +96,15 @@ uint32_t
SBDeclaration::GetLine () const
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
uint32_t line = 0;
if (m_opaque_ap.get())
line = m_opaque_ap->GetLine();
-
+
if (log)
- log->Printf ("SBLineEntry(%p)::GetLine () => %u", m_opaque_ap.get(), line);
-
+ log->Printf ("SBLineEntry(%p)::GetLine () => %u",
+ static_cast<void*>(m_opaque_ap.get()), line);
+
return line;
}
diff --git a/source/API/SBError.cpp b/source/API/SBError.cpp
index bd6b54300f60..157997b2502f 100644
--- a/source/API/SBError.cpp
+++ b/source/API/SBError.cpp
@@ -77,7 +77,8 @@ SBError::Fail () const
ret_value = m_opaque_ap->Fail();
if (log)
- log->Printf ("SBError(%p)::Fail () => %i", m_opaque_ap.get(), ret_value);
+ log->Printf ("SBError(%p)::Fail () => %i",
+ static_cast<void*>(m_opaque_ap.get()), ret_value);
return ret_value;
}
@@ -91,7 +92,8 @@ SBError::Success () const
ret_value = m_opaque_ap->Success();
if (log)
- log->Printf ("SBError(%p)::Success () => %i", m_opaque_ap.get(), ret_value);
+ log->Printf ("SBError(%p)::Success () => %i",
+ static_cast<void*>(m_opaque_ap.get()), ret_value);
return ret_value;
}
@@ -106,7 +108,8 @@ SBError::GetError () const
err = m_opaque_ap->GetError();
if (log)
- log->Printf ("SBError(%p)::GetError () => 0x%8.8x", m_opaque_ap.get(), err);
+ log->Printf ("SBError(%p)::GetError () => 0x%8.8x",
+ static_cast<void*>(m_opaque_ap.get()), err);
return err;
@@ -121,7 +124,8 @@ SBError::GetType () const
err_type = m_opaque_ap->GetType();
if (log)
- log->Printf ("SBError(%p)::GetType () => %i", m_opaque_ap.get(), err_type);
+ log->Printf ("SBError(%p)::GetType () => %i",
+ static_cast<void*>(m_opaque_ap.get()), err_type);
return err_type;
}
diff --git a/source/API/SBEvent.cpp b/source/API/SBEvent.cpp
index d5d4a84bc1fd..57a699fd739d 100644
--- a/source/API/SBEvent.cpp
+++ b/source/API/SBEvent.cpp
@@ -92,9 +92,11 @@ SBEvent::GetType () const
{
StreamString sstr;
if (lldb_event && lldb_event->GetBroadcaster() && lldb_event->GetBroadcaster()->GetEventNames(sstr, event_type, true))
- log->Printf ("SBEvent(%p)::GetType () => 0x%8.8x (%s)", get(), event_type, sstr.GetData());
+ log->Printf ("SBEvent(%p)::GetType () => 0x%8.8x (%s)",
+ static_cast<void*>(get()), event_type, sstr.GetData());
else
- log->Printf ("SBEvent(%p)::GetType () => 0x%8.8x", get(), event_type);
+ log->Printf ("SBEvent(%p)::GetType () => 0x%8.8x",
+ static_cast<void*>(get()), event_type);
}
@@ -141,11 +143,10 @@ SBEvent::BroadcasterMatchesRef (const SBBroadcaster &broadcaster)
// For logging, this gets a little chatty so only enable this when verbose logging is on
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API | LIBLLDB_LOG_VERBOSE));
if (log)
- log->Printf ("SBEvent(%p)::BroadcasterMatchesRef (SBBroadcaster(%p): %s) => %i",
- get(),
- broadcaster.get(),
- broadcaster.GetName(),
- success);
+ log->Printf ("SBEvent(%p)::BroadcasterMatchesRef (SBBroadcaster(%p): %s) => %i",
+ static_cast<void*>(get()),
+ static_cast<void*>(broadcaster.get()),
+ broadcaster.GetName(), success);
return success;
}
@@ -206,8 +207,8 @@ SBEvent::GetCStringFromEvent (const SBEvent &event)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBEvent(%p)::GetCStringFromEvent () => \"%s\"",
- event.get(),
+ log->Printf ("SBEvent(%p)::GetCStringFromEvent () => \"%s\"",
+ static_cast<void*>(event.get()),
reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event.get())));
return reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event.get()));
diff --git a/source/API/SBExpressionOptions.cpp b/source/API/SBExpressionOptions.cpp
index ae1c8f99df30..448ff4cf6dd6 100644
--- a/source/API/SBExpressionOptions.cpp
+++ b/source/API/SBExpressionOptions.cpp
@@ -101,6 +101,18 @@ SBExpressionOptions::SetTimeoutInMicroSeconds (uint32_t timeout)
m_opaque_ap->SetTimeoutUsec (timeout);
}
+uint32_t
+SBExpressionOptions::GetOneThreadTimeoutInMicroSeconds () const
+{
+ return m_opaque_ap->GetOneThreadTimeoutUsec ();
+}
+
+void
+SBExpressionOptions::SetOneThreadTimeoutInMicroSeconds (uint32_t timeout)
+{
+ m_opaque_ap->SetOneThreadTimeoutUsec (timeout);
+}
+
bool
SBExpressionOptions::GetTryAllThreads () const
{
@@ -114,6 +126,18 @@ SBExpressionOptions::SetTryAllThreads (bool run_others)
}
bool
+SBExpressionOptions::GetStopOthers () const
+{
+ return m_opaque_ap->GetStopOthers ();
+}
+
+void
+SBExpressionOptions::SetStopOthers (bool run_others)
+{
+ m_opaque_ap->SetStopOthers (run_others);
+}
+
+bool
SBExpressionOptions::GetTrapExceptions () const
{
return m_opaque_ap->GetTrapExceptions ();
@@ -125,6 +149,43 @@ SBExpressionOptions::SetTrapExceptions (bool trap_exceptions)
m_opaque_ap->SetTrapExceptions (trap_exceptions);
}
+void
+SBExpressionOptions::SetLanguage (lldb::LanguageType language)
+{
+ m_opaque_ap->SetLanguage(language);
+}
+
+void
+SBExpressionOptions::SetCancelCallback (lldb::ExpressionCancelCallback callback, void *baton)
+{
+ m_opaque_ap->SetCancelCallback (callback, baton);
+}
+
+bool
+SBExpressionOptions::GetGenerateDebugInfo ()
+{
+ return m_opaque_ap->GetGenerateDebugInfo();
+}
+
+void
+SBExpressionOptions::SetGenerateDebugInfo (bool b)
+{
+ return m_opaque_ap->SetGenerateDebugInfo(b);
+}
+
+bool
+SBExpressionOptions::GetSuppressPersistentResult ()
+{
+ return m_opaque_ap->GetResultIsInternal ();
+}
+
+void
+SBExpressionOptions::SetSuppressPersistentResult (bool b)
+{
+ return m_opaque_ap->SetResultIsInternal (b);
+}
+
+
EvaluateExpressionOptions *
SBExpressionOptions::get() const
{
diff --git a/source/API/SBFileSpec.cpp b/source/API/SBFileSpec.cpp
index 4fd2866c9b05..8d63fc587d81 100644
--- a/source/API/SBFileSpec.cpp
+++ b/source/API/SBFileSpec.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include <inttypes.h> // PRIu64
#include <limits.h>
#include "lldb/API/SBFileSpec.h"
@@ -15,6 +16,8 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
+#include "llvm/ADT/SmallString.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -35,7 +38,7 @@ SBFileSpec::SBFileSpec (const lldb_private::FileSpec& fspec) :
{
}
-// Deprected!!!
+// Deprecated!!!
SBFileSpec::SBFileSpec (const char *path) :
m_opaque_ap(new FileSpec (path, true))
{
@@ -72,7 +75,9 @@ SBFileSpec::Exists () const
bool result = m_opaque_ap->Exists();
if (log)
- log->Printf ("SBFileSpec(%p)::Exists () => %s", m_opaque_ap.get(), (result ? "true" : "false"));
+ log->Printf ("SBFileSpec(%p)::Exists () => %s",
+ static_cast<void*>(m_opaque_ap.get()),
+ (result ? "true" : "false"));
return result;
}
@@ -86,7 +91,11 @@ SBFileSpec::ResolveExecutableLocation ()
int
SBFileSpec::ResolvePath (const char *src_path, char *dst_path, size_t dst_len)
{
- return lldb_private::FileSpec::Resolve (src_path, dst_path, 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;
}
const char *
@@ -98,9 +107,11 @@ SBFileSpec::GetFilename() const
if (log)
{
if (s)
- log->Printf ("SBFileSpec(%p)::GetFilename () => \"%s\"", m_opaque_ap.get(), s);
+ log->Printf ("SBFileSpec(%p)::GetFilename () => \"%s\"",
+ static_cast<void*>(m_opaque_ap.get()), s);
else
- log->Printf ("SBFileSpec(%p)::GetFilename () => NULL", m_opaque_ap.get());
+ log->Printf ("SBFileSpec(%p)::GetFilename () => NULL",
+ static_cast<void*>(m_opaque_ap.get()));
}
return s;
@@ -114,9 +125,11 @@ SBFileSpec::GetDirectory() const
if (log)
{
if (s)
- log->Printf ("SBFileSpec(%p)::GetDirectory () => \"%s\"", m_opaque_ap.get(), s);
+ log->Printf ("SBFileSpec(%p)::GetDirectory () => \"%s\"",
+ static_cast<void*>(m_opaque_ap.get()), s);
else
- log->Printf ("SBFileSpec(%p)::GetDirectory () => NULL", m_opaque_ap.get());
+ log->Printf ("SBFileSpec(%p)::GetDirectory () => NULL",
+ static_cast<void*>(m_opaque_ap.get()));
}
return s;
}
@@ -148,7 +161,8 @@ SBFileSpec::GetPath (char *dst_path, size_t dst_len) const
if (log)
log->Printf ("SBFileSpec(%p)::GetPath (dst_path=\"%.*s\", dst_len=%" PRIu64 ") => %u",
- m_opaque_ap.get(), result, dst_path, (uint64_t)dst_len, result);
+ static_cast<void*>(m_opaque_ap.get()), result, dst_path,
+ static_cast<uint64_t>(dst_len), result);
if (result == 0 && dst_path && dst_len > 0)
*dst_path = '\0';
diff --git a/source/API/SBFileSpecList.cpp b/source/API/SBFileSpecList.cpp
index 3ebf3cc80a2a..a457a754f0d0 100644
--- a/source/API/SBFileSpecList.cpp
+++ b/source/API/SBFileSpecList.cpp
@@ -38,7 +38,8 @@ SBFileSpecList::SBFileSpecList (const SBFileSpecList &rhs) :
if (log)
{
log->Printf ("SBFileSpecList::SBFileSpecList (const SBFileSpecList rhs.ap=%p) => SBFileSpecList(%p)",
- rhs.m_opaque_ap.get(), m_opaque_ap.get());
+ static_cast<void*>(rhs.m_opaque_ap.get()),
+ static_cast<void*>(m_opaque_ap.get()));
}
}
diff --git a/source/API/SBFrame.cpp b/source/API/SBFrame.cpp
index 44fc654c44b6..325f40fd5b56 100644
--- a/source/API/SBFrame.cpp
+++ b/source/API/SBFrame.cpp
@@ -63,9 +63,9 @@ SBFrame::SBFrame (const StackFrameSP &lldb_object_sp) :
{
SBStream sstr;
GetDescription (sstr);
- log->Printf ("SBFrame::SBFrame (sp=%p) => SBFrame(%p): %s",
- lldb_object_sp.get(), lldb_object_sp.get(), sstr.GetData());
-
+ log->Printf ("SBFrame::SBFrame (sp=%p) => SBFrame(%p): %s",
+ static_cast<void*>(lldb_object_sp.get()),
+ static_cast<void*>(lldb_object_sp.get()), sstr.GetData());
}
}
@@ -141,8 +141,9 @@ SBFrame::GetSymbolContext (uint32_t resolve_scope) const
}
if (log)
- log->Printf ("SBFrame(%p)::GetSymbolContext (resolve_scope=0x%8.8x) => SBSymbolContext(%p)",
- frame, resolve_scope, sb_sym_ctx.get());
+ log->Printf ("SBFrame(%p)::GetSymbolContext (resolve_scope=0x%8.8x) => SBSymbolContext(%p)",
+ static_cast<void*>(frame), resolve_scope,
+ static_cast<void*>(sb_sym_ctx.get()));
return sb_sym_ctx;
}
@@ -184,8 +185,9 @@ SBFrame::GetModule () const
}
if (log)
- log->Printf ("SBFrame(%p)::GetModule () => SBModule(%p)",
- frame, module_sp.get());
+ log->Printf ("SBFrame(%p)::GetModule () => SBModule(%p)",
+ static_cast<void*>(frame),
+ static_cast<void*>(module_sp.get()));
return sb_module;
}
@@ -224,8 +226,9 @@ SBFrame::GetCompileUnit () const
}
}
if (log)
- log->Printf ("SBFrame(%p)::GetCompileUnit () => SBCompileUnit(%p)",
- frame, sb_comp_unit.get());
+ log->Printf ("SBFrame(%p)::GetCompileUnit () => SBCompileUnit(%p)",
+ static_cast<void*>(frame),
+ static_cast<void*>(sb_comp_unit.get()));
return sb_comp_unit;
}
@@ -264,8 +267,9 @@ SBFrame::GetFunction () const
}
}
if (log)
- log->Printf ("SBFrame(%p)::GetFunction () => SBFunction(%p)",
- frame, sb_function.get());
+ log->Printf ("SBFrame(%p)::GetFunction () => SBFunction(%p)",
+ static_cast<void*>(frame),
+ static_cast<void*>(sb_function.get()));
return sb_function;
}
@@ -304,8 +308,9 @@ SBFrame::GetSymbol () const
}
}
if (log)
- log->Printf ("SBFrame(%p)::GetSymbol () => SBSymbol(%p)",
- frame, sb_symbol.get());
+ log->Printf ("SBFrame(%p)::GetSymbol () => SBSymbol(%p)",
+ static_cast<void*>(frame),
+ static_cast<void*>(sb_symbol.get()));
return sb_symbol;
}
@@ -339,12 +344,14 @@ SBFrame::GetBlock () const
else
{
if (log)
- log->Printf ("SBFrame(%p)::GetBlock () => error: process is running", frame);
+ log->Printf ("SBFrame(%p)::GetBlock () => error: process is running",
+ static_cast<void*>(frame));
}
}
if (log)
- log->Printf ("SBFrame(%p)::GetBlock () => SBBlock(%p)",
- frame, sb_block.GetPtr());
+ log->Printf ("SBFrame(%p)::GetBlock () => SBBlock(%p)",
+ static_cast<void*>(frame),
+ static_cast<void*>(sb_block.GetPtr()));
return sb_block;
}
@@ -382,8 +389,9 @@ SBFrame::GetFrameBlock () const
}
}
if (log)
- log->Printf ("SBFrame(%p)::GetFrameBlock () => SBBlock(%p)",
- frame, sb_block.GetPtr());
+ log->Printf ("SBFrame(%p)::GetFrameBlock () => SBBlock(%p)",
+ static_cast<void*>(frame),
+ static_cast<void*>(sb_block.GetPtr()));
return sb_block;
}
@@ -421,8 +429,9 @@ SBFrame::GetLineEntry () const
}
}
if (log)
- log->Printf ("SBFrame(%p)::GetLineEntry () => SBLineEntry(%p)",
- frame, sb_line_entry.get());
+ log->Printf ("SBFrame(%p)::GetLineEntry () => SBLineEntry(%p)",
+ static_cast<void*>(frame),
+ static_cast<void*>(sb_line_entry.get()));
return sb_line_entry;
}
@@ -430,16 +439,16 @@ uint32_t
SBFrame::GetFrameID () const
{
uint32_t frame_idx = UINT32_MAX;
-
+
ExecutionContext exe_ctx(m_opaque_sp.get());
StackFrame *frame = exe_ctx.GetFramePtr();
if (frame)
frame_idx = frame->GetFrameIndex ();
-
+
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBFrame(%p)::GetFrameID () => %u",
- frame, frame_idx);
+ log->Printf ("SBFrame(%p)::GetFrameID () => %u",
+ static_cast<void*>(frame), frame_idx);
return frame_idx;
}
@@ -478,7 +487,8 @@ SBFrame::GetPC () const
}
if (log)
- log->Printf ("SBFrame(%p)::GetPC () => 0x%" PRIx64, frame, addr);
+ log->Printf ("SBFrame(%p)::GetPC () => 0x%" PRIx64,
+ static_cast<void*>(frame), addr);
return addr;
}
@@ -519,7 +529,7 @@ SBFrame::SetPC (addr_t new_pc)
if (log)
log->Printf ("SBFrame(%p)::SetPC (new_pc=0x%" PRIx64 ") => %i",
- frame, new_pc, ret_val);
+ static_cast<void*>(frame), new_pc, ret_val);
return ret_val;
}
@@ -558,7 +568,8 @@ SBFrame::GetSP () const
}
}
if (log)
- log->Printf ("SBFrame(%p)::GetSP () => 0x%" PRIx64, frame, addr);
+ log->Printf ("SBFrame(%p)::GetSP () => 0x%" PRIx64,
+ static_cast<void*>(frame), addr);
return addr;
}
@@ -599,7 +610,8 @@ SBFrame::GetFP () const
}
if (log)
- log->Printf ("SBFrame(%p)::GetFP () => 0x%" PRIx64, frame, addr);
+ log->Printf ("SBFrame(%p)::GetFP () => 0x%" PRIx64,
+ static_cast<void*>(frame), addr);
return addr;
}
@@ -638,7 +650,9 @@ SBFrame::GetPCAddress () const
}
}
if (log)
- log->Printf ("SBFrame(%p)::GetPCAddress () => SBAddress(%p)", frame, sb_addr.get());
+ log->Printf ("SBFrame(%p)::GetPCAddress () => SBAddress(%p)",
+ static_cast<void*>(frame),
+ static_cast<void*>(sb_addr.get()));
return sb_addr;
}
@@ -727,7 +741,6 @@ SBFrame::FindVariable (const char *name)
}
return value;
}
-
SBValue
SBFrame::FindVariable (const char *name, lldb::DynamicValueType use_dynamic)
@@ -742,7 +755,7 @@ SBFrame::FindVariable (const char *name, lldb::DynamicValueType use_dynamic)
log->Printf ("SBFrame::FindVariable called with empty name");
return sb_value;
}
-
+
ValueObjectSP value_sp;
Mutex::Locker api_locker;
ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
@@ -766,7 +779,7 @@ SBFrame::FindVariable (const char *name, lldb::DynamicValueType use_dynamic)
const bool can_create = true;
const bool get_parent_variables = true;
const bool stop_if_block_is_inlined_function = true;
-
+
if (sc.block->AppendVariables (can_create,
get_parent_variables,
stop_if_block_is_inlined_function,
@@ -794,10 +807,11 @@ SBFrame::FindVariable (const char *name, lldb::DynamicValueType use_dynamic)
log->Printf ("SBFrame::FindVariable () => error: process is running");
}
}
-
+
if (log)
- log->Printf ("SBFrame(%p)::FindVariable (name=\"%s\") => SBValue(%p)",
- frame, name, value_sp.get());
+ log->Printf ("SBFrame(%p)::FindVariable (name=\"%s\") => SBValue(%p)",
+ static_cast<void*>(frame), name,
+ static_cast<void*>(value_sp.get()));
return sb_value;
}
@@ -822,14 +836,14 @@ SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueTy
{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
SBValue sb_value;
-
+
if (name == NULL || name[0] == '\0')
{
if (log)
log->Printf ("SBFrame::FindValue called with empty name.");
return sb_value;
}
-
+
ValueObjectSP value_sp;
Mutex::Locker api_locker;
ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
@@ -846,7 +860,7 @@ SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueTy
if (frame)
{
VariableList variable_list;
-
+
switch (value_type)
{
case eValueTypeVariableGlobal: // global variable
@@ -854,7 +868,6 @@ 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));
const bool can_create = true;
@@ -957,12 +970,12 @@ SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueTy
log->Printf ("SBFrame::FindValue () => error: process is running");
}
}
-
+
if (log)
- log->Printf ("SBFrame(%p)::FindVariableInScope (name=\"%s\", value_type=%i) => SBValue(%p)",
- frame, name, value_type, value_sp.get());
+ log->Printf ("SBFrame(%p)::FindVariableInScope (name=\"%s\", value_type=%i) => SBValue(%p)",
+ static_cast<void*>(frame), name, value_type,
+ static_cast<void*>(value_sp.get()));
-
return sb_value;
}
@@ -999,10 +1012,9 @@ SBFrame::GetThread () const
{
SBStream sstr;
sb_thread.GetDescription (sstr);
- log->Printf ("SBFrame(%p)::GetThread () => SBThread(%p): %s",
- exe_ctx.GetFramePtr(),
- thread_sp.get(),
- sstr.GetData());
+ log->Printf ("SBFrame(%p)::GetThread () => SBThread(%p): %s",
+ static_cast<void*>(exe_ctx.GetFramePtr()),
+ static_cast<void*>(thread_sp.get()), sstr.GetData());
}
return sb_thread;
@@ -1039,11 +1051,12 @@ SBFrame::Disassemble () const
{
if (log)
log->Printf ("SBFrame::Disassemble () => error: process is running");
- }
+ }
}
if (log)
- log->Printf ("SBFrame(%p)::Disassemble () => %s", frame, disassembly);
+ log->Printf ("SBFrame(%p)::Disassemble () => %s",
+ static_cast<void*>(frame), disassembly);
return disassembly;
}
@@ -1084,12 +1097,9 @@ SBFrame::GetVariables (bool arguments,
Target *target = exe_ctx.GetTargetPtr();
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)",
+ arguments, locals, statics, in_scope_only);
+
Process *process = exe_ctx.GetProcessPtr();
if (target && process)
{
@@ -1156,13 +1166,13 @@ SBFrame::GetVariables (bool arguments,
{
if (log)
log->Printf ("SBFrame::GetVariables () => error: process is running");
- }
+ }
}
if (log)
- {
- log->Printf ("SBFrame(%p)::GetVariables (...) => SBValueList(%p)", frame, value_list.opaque_ptr());
- }
+ log->Printf ("SBFrame(%p)::GetVariables (...) => SBValueList(%p)",
+ static_cast<void*>(frame),
+ static_cast<void*>(value_list.opaque_ptr()));
return value_list;
}
@@ -1207,11 +1217,13 @@ SBFrame::GetRegisters ()
{
if (log)
log->Printf ("SBFrame::GetRegisters () => error: process is running");
- }
+ }
}
if (log)
- log->Printf ("SBFrame(%p)::GetRegisters () => SBValueList(%p)", frame, value_list.opaque_ptr());
+ log->Printf ("SBFrame(%p)::GetRegisters () => SBValueList(%p)",
+ static_cast<void*>(frame),
+ static_cast<void*>(value_list.opaque_ptr()));
return value_list;
}
@@ -1265,11 +1277,13 @@ SBFrame::FindRegister (const char *name)
{
if (log)
log->Printf ("SBFrame::FindRegister () => error: process is running");
- }
+ }
}
if (log)
- log->Printf ("SBFrame(%p)::FindRegister () => SBValue(%p)", frame, value_sp.get());
+ log->Printf ("SBFrame(%p)::FindRegister () => SBValue(%p)",
+ static_cast<void*>(frame),
+ static_cast<void*>(value_sp.get()));
return result;
}
@@ -1355,19 +1369,19 @@ lldb::SBValue
SBFrame::EvaluateExpression (const char *expr, const SBExpressionOptions &options)
{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
Log *expr_log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
- ExecutionResults exe_results = eExecutionSetupError;
+ ExpressionResults exe_results = eExpressionSetupError;
SBValue expr_result;
-
+
if (expr == NULL || expr[0] == '\0')
{
if (log)
log->Printf ("SBFrame::EvaluateExpression called with an empty expression");
return expr_result;
}
-
+
ValueObjectSP expr_value_sp;
Mutex::Locker api_locker;
@@ -1379,7 +1393,7 @@ SBFrame::EvaluateExpression (const char *expr, const SBExpressionOptions &option
StackFrame *frame = NULL;
Target *target = exe_ctx.GetTargetPtr();
Process *process = exe_ctx.GetProcessPtr();
-
+
if (target && process)
{
Process::StopLocker stop_locker;
@@ -1395,7 +1409,7 @@ SBFrame::EvaluateExpression (const char *expr, const SBExpressionOptions &option
Host::SetCrashDescriptionWithFormat ("SBFrame::EvaluateExpression (expr = \"%s\", fetch_dynamic_value = %u) %s",
expr, options.GetFetchDynamicValue(), frame_description.GetString().c_str());
}
-
+
exe_results = target->EvaluateExpression (expr,
frame,
expr_value_sp,
@@ -1415,21 +1429,18 @@ SBFrame::EvaluateExpression (const char *expr, const SBExpressionOptions &option
{
if (log)
log->Printf ("SBFrame::EvaluateExpression () => error: process is running");
- }
+ }
}
#ifndef LLDB_DISABLE_PYTHON
if (expr_log)
- expr_log->Printf("** [SBFrame::EvaluateExpression] Expression result is %s, summary %s **",
- expr_result.GetValue(),
- expr_result.GetSummary());
-
+ expr_log->Printf("** [SBFrame::EvaluateExpression] Expression result is %s, summary %s **",
+ expr_result.GetValue(), expr_result.GetSummary());
+
if (log)
- log->Printf ("SBFrame(%p)::EvaluateExpression (expr=\"%s\") => SBValue(%p) (execution result=%d)",
- frame,
- expr,
- expr_value_sp.get(),
- exe_results);
+ log->Printf ("SBFrame(%p)::EvaluateExpression (expr=\"%s\") => SBValue(%p) (execution result=%d)",
+ static_cast<void*>(frame), expr,
+ static_cast<void*>(expr_value_sp.get()), exe_results);
#endif
return expr_result;
diff --git a/source/API/SBFunction.cpp b/source/API/SBFunction.cpp
index bb7ea2e9f202..3d185da17f26 100644
--- a/source/API/SBFunction.cpp
+++ b/source/API/SBFunction.cpp
@@ -66,9 +66,11 @@ SBFunction::GetName() const
if (log)
{
if (cstr)
- log->Printf ("SBFunction(%p)::GetName () => \"%s\"", m_opaque_ptr, cstr);
+ log->Printf ("SBFunction(%p)::GetName () => \"%s\"",
+ static_cast<void*>(m_opaque_ptr), cstr);
else
- log->Printf ("SBFunction(%p)::GetName () => NULL", m_opaque_ptr);
+ log->Printf ("SBFunction(%p)::GetName () => NULL",
+ static_cast<void*>(m_opaque_ptr));
}
return cstr;
}
@@ -83,9 +85,11 @@ SBFunction::GetMangledName () const
if (log)
{
if (cstr)
- log->Printf ("SBFunction(%p)::GetMangledName () => \"%s\"", m_opaque_ptr, cstr);
+ log->Printf ("SBFunction(%p)::GetMangledName () => \"%s\"",
+ static_cast<void*>(m_opaque_ptr), cstr);
else
- log->Printf ("SBFunction(%p)::GetMangledName () => NULL", m_opaque_ptr);
+ log->Printf ("SBFunction(%p)::GetMangledName () => NULL",
+ static_cast<void*>(m_opaque_ptr));
}
return cstr;
}
diff --git a/source/API/SBHostOS.cpp b/source/API/SBHostOS.cpp
index 166403103ad5..ec1e2f2e9cba 100644
--- a/source/API/SBHostOS.cpp
+++ b/source/API/SBHostOS.cpp
@@ -12,6 +12,7 @@
#include "lldb/Host/FileSpec.h"
#include "lldb/Core/Log.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
using namespace lldb;
using namespace lldb_private;
@@ -22,7 +23,7 @@ SBFileSpec
SBHostOS::GetProgramFileSpec ()
{
SBFileSpec sb_filespec;
- sb_filespec.SetFileSpec (Host::GetProgramFileSpec ());
+ sb_filespec.SetFileSpec(HostInfo::GetProgramFileSpec());
return sb_filespec;
}
@@ -31,18 +32,29 @@ SBHostOS::GetLLDBPythonPath ()
{
SBFileSpec sb_lldb_python_filespec;
FileSpec lldb_python_spec;
- if (Host::GetLLDBPath (ePathTypePythonDir, lldb_python_spec))
+ if (HostInfo::GetLLDBPath(ePathTypePythonDir, lldb_python_spec))
{
sb_lldb_python_filespec.SetFileSpec (lldb_python_spec);
}
return sb_lldb_python_filespec;
}
+
+SBFileSpec
+SBHostOS::GetLLDBPath (lldb::PathType path_type)
+{
+ SBFileSpec sb_fspec;
+ FileSpec fspec;
+ if (HostInfo::GetLLDBPath(path_type, fspec))
+ sb_fspec.SetFileSpec (fspec);
+ return sb_fspec;
+}
+
lldb::thread_t
SBHostOS::ThreadCreate
(
const char *name,
- thread_func_t thread_function,
+ lldb::thread_func_t thread_function,
void *thread_arg,
SBError *error_ptr
)
@@ -50,8 +62,10 @@ SBHostOS::ThreadCreate
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBHostOS::ThreadCreate (name=\"%s\", thread_function=%p, thread_arg=%p, error_ptr=%p)", name,
- thread_function, thread_arg, error_ptr);
+ log->Printf ("SBHostOS::ThreadCreate (name=\"%s\", thread_function=%p, thread_arg=%p, error_ptr=%p)",
+ name, reinterpret_cast<void*>(reinterpret_cast<intptr_t>(thread_function)),
+ static_cast<void*>(thread_arg),
+ static_cast<void*>(error_ptr));
// FIXME: You should log the return value?
@@ -77,7 +91,7 @@ SBHostOS::ThreadDetach (lldb::thread_t thread, SBError *error_ptr)
}
bool
-SBHostOS::ThreadJoin (lldb::thread_t thread, thread_result_t *result, SBError *error_ptr)
+SBHostOS::ThreadJoin (lldb::thread_t thread, lldb::thread_result_t *result, SBError *error_ptr)
{
return Host::ThreadJoin (thread, result, error_ptr ? error_ptr->get() : NULL);
}
diff --git a/source/API/SBLineEntry.cpp b/source/API/SBLineEntry.cpp
index 0864a2e006c3..833eea3e35c4 100644
--- a/source/API/SBLineEntry.cpp
+++ b/source/API/SBLineEntry.cpp
@@ -66,7 +66,6 @@ SBLineEntry::~SBLineEntry ()
SBAddress
SBLineEntry::GetStartAddress () const
{
-
SBAddress sb_address;
if (m_opaque_ap.get())
sb_address.SetAddress(&m_opaque_ap->range.GetBaseAddress());
@@ -78,8 +77,9 @@ SBLineEntry::GetStartAddress () const
const Address *addr = sb_address.get();
if (addr)
addr->Dump (&sstr, NULL, Address::DumpStyleModuleWithFileAddress, Address::DumpStyleInvalid, 4);
- log->Printf ("SBLineEntry(%p)::GetStartAddress () => SBAddress (%p): %s",
- m_opaque_ap.get(), sb_address.get(), sstr.GetData());
+ log->Printf ("SBLineEntry(%p)::GetStartAddress () => SBAddress (%p): %s",
+ static_cast<void*>(m_opaque_ap.get()),
+ static_cast<void*>(sb_address.get()), sstr.GetData());
}
return sb_address;
@@ -101,8 +101,9 @@ SBLineEntry::GetEndAddress () const
const Address *addr = sb_address.get();
if (addr)
addr->Dump (&sstr, NULL, Address::DumpStyleModuleWithFileAddress, Address::DumpStyleInvalid, 4);
- log->Printf ("SBLineEntry(%p)::GetEndAddress () => SBAddress (%p): %s",
- m_opaque_ap.get(), sb_address.get(), sstr.GetData());
+ log->Printf ("SBLineEntry(%p)::GetEndAddress () => SBAddress (%p): %s",
+ static_cast<void*>(m_opaque_ap.get()),
+ static_cast<void*>(sb_address.get()), sstr.GetData());
}
return sb_address;
}
@@ -127,8 +128,10 @@ SBLineEntry::GetFileSpec () const
{
SBStream sstr;
sb_file_spec.GetDescription (sstr);
- log->Printf ("SBLineEntry(%p)::GetFileSpec () => SBFileSpec(%p): %s", m_opaque_ap.get(),
- sb_file_spec.get(), sstr.GetData());
+ log->Printf ("SBLineEntry(%p)::GetFileSpec () => SBFileSpec(%p): %s",
+ static_cast<void*>(m_opaque_ap.get()),
+ static_cast<const void*>(sb_file_spec.get()),
+ sstr.GetData());
}
return sb_file_spec;
@@ -144,7 +147,8 @@ SBLineEntry::GetLine () const
line = m_opaque_ap->line;
if (log)
- log->Printf ("SBLineEntry(%p)::GetLine () => %u", m_opaque_ap.get(), line);
+ log->Printf ("SBLineEntry(%p)::GetLine () => %u",
+ static_cast<void*>(m_opaque_ap.get()), line);
return line;
}
diff --git a/source/API/SBListener.cpp b/source/API/SBListener.cpp
index 2e67b4c24e86..bad9ba82bc91 100644
--- a/source/API/SBListener.cpp
+++ b/source/API/SBListener.cpp
@@ -42,7 +42,7 @@ SBListener::SBListener (const char *name) :
if (log)
log->Printf ("SBListener::SBListener (name=\"%s\") => SBListener(%p)",
- name, m_opaque_ptr);
+ name, static_cast<void*>(m_opaque_ptr));
}
@@ -110,7 +110,7 @@ SBListener::StartListeningForEventClass (SBDebugger &debugger,
else
return 0;
}
-
+
bool
SBListener::StopListeningForEventClass (SBDebugger &debugger,
const char *broadcaster_class,
@@ -127,7 +127,7 @@ SBListener::StopListeningForEventClass (SBDebugger &debugger,
else
return false;
}
-
+
uint32_t
SBListener::StartListeningForEvents (const SBBroadcaster& broadcaster, uint32_t event_mask)
{
@@ -136,23 +136,23 @@ SBListener::StartListeningForEvents (const SBBroadcaster& broadcaster, uint32_t
{
acquired_event_mask = m_opaque_ptr->StartListeningForEvents (broadcaster.get(), event_mask);
}
-
+
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API);
if (log)
{
StreamString sstr_requested;
StreamString sstr_acquired;
-
+
Broadcaster *lldb_broadcaster = broadcaster.get();
if (lldb_broadcaster)
{
const bool got_requested_names = lldb_broadcaster->GetEventNames (sstr_requested, event_mask, false);
const bool got_acquired_names = lldb_broadcaster->GetEventNames (sstr_acquired, acquired_event_mask, false);
log->Printf ("SBListener(%p)::StartListeneingForEvents (SBBroadcaster(%p): %s, event_mask=0x%8.8x%s%s%s) => 0x%8.8x%s%s%s",
- m_opaque_ptr,
- lldb_broadcaster,
- lldb_broadcaster->GetBroadcasterName().GetCString(),
- event_mask,
+ static_cast<void*>(m_opaque_ptr),
+ static_cast<void*>(lldb_broadcaster),
+ lldb_broadcaster->GetBroadcasterName().GetCString(),
+ event_mask,
got_requested_names ? " (" : "",
sstr_requested.GetData(),
got_requested_names ? ")" : "",
@@ -163,12 +163,10 @@ SBListener::StartListeningForEvents (const SBBroadcaster& broadcaster, uint32_t
}
else
{
- log->Printf ("SBListener(%p)::StartListeneingForEvents (SBBroadcaster(%p), event_mask=0x%8.8x) => 0x%8.8x",
- m_opaque_ptr,
- lldb_broadcaster,
- event_mask,
+ log->Printf ("SBListener(%p)::StartListeneingForEvents (SBBroadcaster(%p), event_mask=0x%8.8x) => 0x%8.8x",
+ static_cast<void*>(m_opaque_ptr),
+ static_cast<void*>(lldb_broadcaster), event_mask,
acquired_event_mask);
-
}
}
@@ -194,12 +192,14 @@ SBListener::WaitForEvent (uint32_t timeout_secs, SBEvent &event)
if (timeout_secs == UINT32_MAX)
{
log->Printf ("SBListener(%p)::WaitForEvent (timeout_secs=INFINITE, SBEvent(%p))...",
- m_opaque_ptr, event.get());
+ static_cast<void*>(m_opaque_ptr),
+ static_cast<void*>(event.get()));
}
else
{
log->Printf ("SBListener(%p)::WaitForEvent (timeout_secs=%d, SBEvent(%p))...",
- m_opaque_ptr, timeout_secs, event.get());
+ static_cast<void*>(m_opaque_ptr), timeout_secs,
+ static_cast<void*>(event.get()));
}
}
bool success = false;
@@ -226,12 +226,14 @@ SBListener::WaitForEvent (uint32_t timeout_secs, SBEvent &event)
if (timeout_secs == UINT32_MAX)
{
log->Printf ("SBListener(%p)::WaitForEvent (timeout_secs=INFINITE, SBEvent(%p)) => %i",
- m_opaque_ptr, event.get(), success);
+ static_cast<void*>(m_opaque_ptr),
+ static_cast<void*>(event.get()), success);
}
else
{
log->Printf ("SBListener(%p)::WaitForEvent (timeout_secs=%d, SBEvent(%p)) => %i",
- m_opaque_ptr, timeout_secs, event.get(), success);
+ static_cast<void*>(m_opaque_ptr), timeout_secs,
+ static_cast<void*>(event.get()), success);
}
}
if (!success)
diff --git a/source/API/SBModule.cpp b/source/API/SBModule.cpp
index c8543d4de298..0d7dda1aa1f7 100644
--- a/source/API/SBModule.cpp
+++ b/source/API/SBModule.cpp
@@ -110,10 +110,9 @@ SBModule::GetFileSpec () const
file_spec.SetFileSpec(module_sp->GetFileSpec());
if (log)
- {
- log->Printf ("SBModule(%p)::GetFileSpec () => SBFileSpec(%p)",
- module_sp.get(), file_spec.get());
- }
+ log->Printf ("SBModule(%p)::GetFileSpec () => SBFileSpec(%p)",
+ static_cast<void*>(module_sp.get()),
+ static_cast<const void*>(file_spec.get()));
return file_spec;
}
@@ -122,20 +121,18 @@ lldb::SBFileSpec
SBModule::GetPlatformFileSpec () const
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
SBFileSpec file_spec;
ModuleSP module_sp (GetSP ());
if (module_sp)
file_spec.SetFileSpec(module_sp->GetPlatformFileSpec());
-
+
if (log)
- {
- log->Printf ("SBModule(%p)::GetPlatformFileSpec () => SBFileSpec(%p)",
- module_sp.get(), file_spec.get());
- }
-
+ log->Printf ("SBModule(%p)::GetPlatformFileSpec () => SBFileSpec(%p)",
+ static_cast<void*>(module_sp.get()),
+ static_cast<const void*>(file_spec.get()));
+
return file_spec;
-
}
bool
@@ -143,22 +140,19 @@ SBModule::SetPlatformFileSpec (const lldb::SBFileSpec &platform_file)
{
bool result = false;
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
ModuleSP module_sp (GetSP ());
if (module_sp)
{
module_sp->SetPlatformFileSpec(*platform_file);
result = true;
}
-
+
if (log)
- {
- log->Printf ("SBModule(%p)::SetPlatformFileSpec (SBFileSpec(%p (%s)) => %i",
- module_sp.get(),
- platform_file.get(),
- platform_file->GetPath().c_str(),
- result);
- }
+ log->Printf ("SBModule(%p)::SetPlatformFileSpec (SBFileSpec(%p (%s)) => %i",
+ static_cast<void*>(module_sp.get()),
+ static_cast<const void*>(platform_file.get()),
+ platform_file->GetPath().c_str(), result);
return result;
}
@@ -201,10 +195,12 @@ SBModule::GetUUIDBytes () const
{
StreamString s;
module_sp->GetUUID().Dump (&s);
- log->Printf ("SBModule(%p)::GetUUIDBytes () => %s", module_sp.get(), s.GetData());
+ log->Printf ("SBModule(%p)::GetUUIDBytes () => %s",
+ static_cast<void*>(module_sp.get()), s.GetData());
}
else
- log->Printf ("SBModule(%p)::GetUUIDBytes () => NULL", module_sp.get());
+ log->Printf ("SBModule(%p)::GetUUIDBytes () => NULL",
+ static_cast<void*>(module_sp.get()));
}
return uuid_bytes;
}
@@ -225,6 +221,7 @@ SBModule::GetUUIDString () const
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;
}
@@ -234,10 +231,12 @@ SBModule::GetUUIDString () const
{
StreamString s;
module_sp->GetUUID().Dump (&s);
- log->Printf ("SBModule(%p)::GetUUIDString () => %s", module_sp.get(), s.GetData());
+ log->Printf ("SBModule(%p)::GetUUIDString () => %s",
+ static_cast<void*>(module_sp.get()), s.GetData());
}
else
- log->Printf ("SBModule(%p)::GetUUIDString () => NULL", module_sp.get());
+ log->Printf ("SBModule(%p)::GetUUIDString () => NULL",
+ static_cast<void*>(module_sp.get()));
}
return uuid_c_string;
}
diff --git a/source/API/SBProcess.cpp b/source/API/SBProcess.cpp
index 235388b5f25c..41efd86177d6 100644
--- a/source/API/SBProcess.cpp
+++ b/source/API/SBProcess.cpp
@@ -40,6 +40,7 @@
#include "lldb/API/SBThread.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBStringList.h"
+#include "lldb/API/SBUnixSignals.h"
using namespace lldb;
using namespace lldb_private;
@@ -148,20 +149,17 @@ SBProcess::RemoteLaunch (char const **argv,
lldb::SBError& error)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
- if (log) {
+ if (log)
log->Printf ("SBProcess(%p)::RemoteLaunch (argv=%p, envp=%p, stdin=%s, stdout=%s, stderr=%s, working-dir=%s, launch_flags=0x%x, stop_at_entry=%i, &error (%p))...",
- m_opaque_wp.lock().get(),
- argv,
- envp,
- stdin_path ? stdin_path : "NULL",
- stdout_path ? stdout_path : "NULL",
- stderr_path ? stderr_path : "NULL",
+ static_cast<void*>(m_opaque_wp.lock().get()),
+ static_cast<void*>(argv), static_cast<void*>(envp),
+ stdin_path ? stdin_path : "NULL",
+ stdout_path ? stdout_path : "NULL",
+ stderr_path ? stderr_path : "NULL",
working_directory ? working_directory : "NULL",
- launch_flags,
- stop_at_entry,
- error.get());
- }
-
+ launch_flags, stop_at_entry,
+ static_cast<void*>(error.get()));
+
ProcessSP process_sp(GetSP());
if (process_sp)
{
@@ -170,7 +168,7 @@ SBProcess::RemoteLaunch (char const **argv,
{
if (stop_at_entry)
launch_flags |= eLaunchFlagStopAtEntry;
- ProcessLaunchInfo launch_info (stdin_path,
+ ProcessLaunchInfo launch_info (stdin_path,
stdout_path,
stderr_path,
working_directory,
@@ -193,13 +191,15 @@ SBProcess::RemoteLaunch (char const **argv,
{
error.SetErrorString ("unable to attach pid");
}
-
+
if (log) {
SBStream sstr;
error.GetDescription (sstr);
- log->Printf ("SBProcess(%p)::RemoteLaunch (...) => SBError (%p): %s", process_sp.get(), error.get(), sstr.GetData());
+ log->Printf ("SBProcess(%p)::RemoteLaunch (...) => SBError (%p): %s",
+ static_cast<void*>(process_sp.get()),
+ static_cast<void*>(error.get()), sstr.GetData());
}
-
+
return error.Success();
}
@@ -214,7 +214,7 @@ SBProcess::RemoteAttachToProcessWithID (lldb::pid_t pid, lldb::SBError& error)
{
ProcessAttachInfo attach_info;
attach_info.SetProcessID (pid);
- error.SetError (process_sp->Attach (attach_info));
+ error.SetError (process_sp->Attach (attach_info));
}
else
{
@@ -230,7 +230,9 @@ SBProcess::RemoteAttachToProcessWithID (lldb::pid_t pid, lldb::SBError& error)
if (log) {
SBStream sstr;
error.GetDescription (sstr);
- log->Printf ("SBProcess(%p)::RemoteAttachToProcessWithID (%" PRIu64 ") => SBError (%p): %s", process_sp.get(), pid, error.get(), sstr.GetData());
+ log->Printf ("SBProcess(%p)::RemoteAttachToProcessWithID (%" PRIu64 ") => SBError (%p): %s",
+ static_cast<void*>(process_sp.get()), pid,
+ static_cast<void*>(error.get()), sstr.GetData());
}
return error.Success();
@@ -247,14 +249,15 @@ SBProcess::GetNumThreads ()
if (process_sp)
{
Process::StopLocker stop_locker;
-
+
const bool can_update = stop_locker.TryLock(&process_sp->GetRunLock());
Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
num_threads = process_sp->GetThreadList().GetSize(can_update);
}
if (log)
- log->Printf ("SBProcess(%p)::GetNumThreads () => %d", process_sp.get(), num_threads);
+ log->Printf ("SBProcess(%p)::GetNumThreads () => %d",
+ static_cast<void*>(process_sp.get()), num_threads);
return num_threads;
}
@@ -275,9 +278,9 @@ SBProcess::GetSelectedThread () const
}
if (log)
- {
- log->Printf ("SBProcess(%p)::GetSelectedThread () => SBThread(%p)", process_sp.get(), thread_sp.get());
- }
+ log->Printf ("SBProcess(%p)::GetSelectedThread () => SBThread(%p)",
+ static_cast<void*>(process_sp.get()),
+ static_cast<void*>(thread_sp.get()));
return sb_thread;
}
@@ -286,7 +289,7 @@ SBThread
SBProcess::CreateOSPluginThread (lldb::tid_t tid, lldb::addr_t context)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
SBThread sb_thread;
ThreadSP thread_sp;
ProcessSP process_sp(GetSP());
@@ -296,10 +299,12 @@ SBProcess::CreateOSPluginThread (lldb::tid_t tid, lldb::addr_t context)
thread_sp = process_sp->CreateOSPluginThread(tid, context);
sb_thread.SetThread (thread_sp);
}
-
+
if (log)
- log->Printf ("SBProcess(%p)::CreateOSPluginThread (tid=0x%" PRIx64 ", context=0x%" PRIx64 ") => SBThread(%p)", process_sp.get(), tid, context, thread_sp.get());
-
+ log->Printf ("SBProcess(%p)::CreateOSPluginThread (tid=0x%" PRIx64 ", context=0x%" PRIx64 ") => SBThread(%p)",
+ static_cast<void*>(process_sp.get()), tid, context,
+ static_cast<void*>(thread_sp.get()));
+
return sb_thread;
}
@@ -316,9 +321,11 @@ SBProcess::GetTarget() const
target_sp = process_sp->GetTarget().shared_from_this();
sb_target.SetSP (target_sp);
}
-
+
if (log)
- log->Printf ("SBProcess(%p)::GetTarget () => SBTarget(%p)", process_sp.get(), target_sp.get());
+ log->Printf ("SBProcess(%p)::GetTarget () => SBTarget(%p)",
+ static_cast<void*>(process_sp.get()),
+ static_cast<void*>(target_sp.get()));
return sb_target;
}
@@ -336,13 +343,12 @@ SBProcess::PutSTDIN (const char *src, size_t src_len)
Error error;
ret_val = process_sp->PutSTDIN (src, src_len, error);
}
-
+
if (log)
- log->Printf ("SBProcess(%p)::PutSTDIN (src=\"%s\", src_len=%d) => %zu",
- process_sp.get(),
- src,
- (uint32_t) src_len,
- ret_val);
+ log->Printf("SBProcess(%p)::PutSTDIN (src=\"%s\", src_len=%" PRIu64 ") => %" PRIu64,
+ static_cast<void*>(process_sp.get()), src,
+ static_cast<uint64_t>(src_len),
+ static_cast<uint64_t>(ret_val));
return ret_val;
}
@@ -357,15 +363,14 @@ SBProcess::GetSTDOUT (char *dst, size_t dst_len) const
Error error;
bytes_read = process_sp->GetSTDOUT (dst, dst_len, error);
}
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
log->Printf ("SBProcess(%p)::GetSTDOUT (dst=\"%.*s\", dst_len=%" PRIu64 ") => %" PRIu64,
- process_sp.get(),
- (int) bytes_read,
- dst,
- (uint64_t)dst_len,
- (uint64_t)bytes_read);
+ static_cast<void*>(process_sp.get()),
+ static_cast<int>(bytes_read), dst,
+ static_cast<uint64_t>(dst_len),
+ static_cast<uint64_t>(bytes_read));
return bytes_read;
}
@@ -384,11 +389,10 @@ SBProcess::GetSTDERR (char *dst, size_t dst_len) const
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
log->Printf ("SBProcess(%p)::GetSTDERR (dst=\"%.*s\", dst_len=%" PRIu64 ") => %" PRIu64,
- process_sp.get(),
- (int) bytes_read,
- dst,
- (uint64_t)dst_len,
- (uint64_t)bytes_read);
+ static_cast<void*>(process_sp.get()),
+ static_cast<int>(bytes_read), dst,
+ static_cast<uint64_t>(dst_len),
+ static_cast<uint64_t>(bytes_read));
return bytes_read;
}
@@ -403,16 +407,15 @@ SBProcess::GetAsyncProfileData(char *dst, size_t dst_len) const
Error error;
bytes_read = process_sp->GetAsyncProfileData (dst, dst_len, error);
}
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
log->Printf ("SBProcess(%p)::GetProfileData (dst=\"%.*s\", dst_len=%" PRIu64 ") => %" PRIu64,
- process_sp.get(),
- (int) bytes_read,
- dst,
- (uint64_t)dst_len,
- (uint64_t)bytes_read);
-
+ static_cast<void*>(process_sp.get()),
+ static_cast<int>(bytes_read), dst,
+ static_cast<uint64_t>(dst_len),
+ static_cast<uint64_t>(bytes_read));
+
return bytes_read;
}
@@ -483,7 +486,8 @@ SBProcess::SetSelectedThreadByID (lldb::tid_t tid)
if (log)
log->Printf ("SBProcess(%p)::SetSelectedThreadByID (tid=0x%4.4" PRIx64 ") => %s",
- process_sp.get(), tid, (ret_val ? "true" : "false"));
+ static_cast<void*>(process_sp.get()), tid,
+ (ret_val ? "true" : "false"));
return ret_val;
}
@@ -502,8 +506,9 @@ SBProcess::SetSelectedThreadByIndexID (uint32_t index_id)
}
if (log)
- log->Printf ("SBProcess(%p)::SetSelectedThreadByID (tid=0x%x) => %s",
- process_sp.get(), index_id, (ret_val ? "true" : "false"));
+ log->Printf ("SBProcess(%p)::SetSelectedThreadByID (tid=0x%x) => %s",
+ static_cast<void*>(process_sp.get()), index_id,
+ (ret_val ? "true" : "false"));
return ret_val;
}
@@ -526,10 +531,10 @@ SBProcess::GetThreadAtIndex (size_t index)
}
if (log)
- {
log->Printf ("SBProcess(%p)::GetThreadAtIndex (index=%d) => SBThread(%p)",
- process_sp.get(), (uint32_t) index, thread_sp.get());
- }
+ static_cast<void*>(process_sp.get()),
+ static_cast<uint32_t>(index),
+ static_cast<void*>(thread_sp.get()));
return sb_thread;
}
@@ -544,13 +549,14 @@ SBProcess::GetNumQueues ()
if (process_sp)
{
Process::StopLocker stop_locker;
-
+
Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
num_queues = process_sp->GetQueueList().GetSize();
}
if (log)
- log->Printf ("SBProcess(%p)::GetNumQueues () => %d", process_sp.get(), num_queues);
+ log->Printf ("SBProcess(%p)::GetNumQueues () => %d",
+ static_cast<void*>(process_sp.get()), num_queues);
return num_queues;
}
@@ -572,10 +578,10 @@ SBProcess::GetQueueAtIndex (size_t index)
}
if (log)
- {
log->Printf ("SBProcess(%p)::GetQueueAtIndex (index=%d) => SBQueue(%p)",
- process_sp.get(), (uint32_t) index, queue_sp.get());
- }
+ static_cast<void*>(process_sp.get()),
+ static_cast<uint32_t>(index),
+ static_cast<void*>(queue_sp.get()));
return sb_queue;
}
@@ -610,8 +616,8 @@ SBProcess::GetState ()
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBProcess(%p)::GetState () => %s",
- process_sp.get(),
+ log->Printf ("SBProcess(%p)::GetState () => %s",
+ static_cast<void*>(process_sp.get()),
lldb_private::StateAsCString (ret_val));
return ret_val;
@@ -630,8 +636,9 @@ SBProcess::GetExitStatus ()
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBProcess(%p)::GetExitStatus () => %i (0x%8.8x)",
- process_sp.get(), exit_status, exit_status);
+ log->Printf ("SBProcess(%p)::GetExitStatus () => %i (0x%8.8x)",
+ static_cast<void*>(process_sp.get()), exit_status,
+ exit_status);
return exit_status;
}
@@ -648,8 +655,8 @@ SBProcess::GetExitDescription ()
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBProcess(%p)::GetExitDescription () => %s",
- process_sp.get(), exit_desc);
+ log->Printf ("SBProcess(%p)::GetExitDescription () => %s",
+ static_cast<void*>(process_sp.get()), exit_desc);
return exit_desc;
}
@@ -663,7 +670,8 @@ SBProcess::GetProcessID ()
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBProcess(%p)::GetProcessID () => %" PRIu64, process_sp.get(), ret_val);
+ log->Printf ("SBProcess(%p)::GetProcessID () => %" PRIu64,
+ static_cast<void*>(process_sp.get()), ret_val);
return ret_val;
}
@@ -677,7 +685,8 @@ SBProcess::GetUniqueID()
ret_val = process_sp->GetUniqueID();
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBProcess(%p)::GetUniqueID () => %" PRIu32, process_sp.get(), ret_val);
+ log->Printf ("SBProcess(%p)::GetUniqueID () => %" PRIu32,
+ static_cast<void*>(process_sp.get()), ret_val);
return ret_val;
}
@@ -688,10 +697,11 @@ SBProcess::GetByteOrder () const
ProcessSP process_sp(GetSP());
if (process_sp)
byteOrder = process_sp->GetTarget().GetArchitecture().GetByteOrder();
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBProcess(%p)::GetByteOrder () => %d", process_sp.get(), byteOrder);
+ log->Printf ("SBProcess(%p)::GetByteOrder () => %d",
+ static_cast<void*>(process_sp.get()), byteOrder);
return byteOrder;
}
@@ -706,7 +716,8 @@ SBProcess::GetAddressByteSize () const
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBProcess(%p)::GetAddressByteSize () => %d", process_sp.get(), size);
+ log->Printf ("SBProcess(%p)::GetAddressByteSize () => %d",
+ static_cast<void*>(process_sp.get()), size);
return size;
}
@@ -715,24 +726,26 @@ SBError
SBProcess::Continue ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
SBError sb_error;
ProcessSP process_sp(GetSP());
if (log)
- log->Printf ("SBProcess(%p)::Continue ()...", process_sp.get());
+ log->Printf ("SBProcess(%p)::Continue ()...",
+ static_cast<void*>(process_sp.get()));
if (process_sp)
{
Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
-
+
Error error (process_sp->Resume());
if (error.Success())
{
if (process_sp->GetTarget().GetDebugger().GetAsyncExecution () == false)
{
if (log)
- log->Printf ("SBProcess(%p)::Continue () waiting for process to stop...", process_sp.get());
+ log->Printf ("SBProcess(%p)::Continue () waiting for process to stop...",
+ static_cast<void*>(process_sp.get()));
process_sp->WaitForProcessToStop (NULL);
}
}
@@ -745,7 +758,9 @@ SBProcess::Continue ()
{
SBStream sstr;
sb_error.GetDescription (sstr);
- log->Printf ("SBProcess(%p)::Continue () => SBError (%p): %s", process_sp.get(), sb_error.get(), sstr.GetData());
+ log->Printf ("SBProcess(%p)::Continue () => SBError (%p): %s",
+ static_cast<void*>(process_sp.get()),
+ static_cast<void*>(sb_error.get()), sstr.GetData());
}
return sb_error;
@@ -770,10 +785,9 @@ SBProcess::Destroy ()
{
SBStream sstr;
sb_error.GetDescription (sstr);
- log->Printf ("SBProcess(%p)::Destroy () => SBError (%p): %s",
- process_sp.get(),
- sb_error.get(),
- sstr.GetData());
+ log->Printf ("SBProcess(%p)::Destroy () => SBError (%p): %s",
+ static_cast<void*>(process_sp.get()),
+ static_cast<void*>(sb_error.get()), sstr.GetData());
}
return sb_error;
@@ -792,16 +806,15 @@ SBProcess::Stop ()
}
else
sb_error.SetErrorString ("SBProcess is invalid");
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
{
SBStream sstr;
sb_error.GetDescription (sstr);
- log->Printf ("SBProcess(%p)::Stop () => SBError (%p): %s",
- process_sp.get(),
- sb_error.get(),
- sstr.GetData());
+ log->Printf ("SBProcess(%p)::Stop () => SBError (%p): %s",
+ static_cast<void*>(process_sp.get()),
+ static_cast<void*>(sb_error.get()), sstr.GetData());
}
return sb_error;
@@ -825,10 +838,9 @@ SBProcess::Kill ()
{
SBStream sstr;
sb_error.GetDescription (sstr);
- log->Printf ("SBProcess(%p)::Kill () => SBError (%p): %s",
- process_sp.get(),
- sb_error.get(),
- sstr.GetData());
+ log->Printf ("SBProcess(%p)::Kill () => SBError (%p): %s",
+ static_cast<void*>(process_sp.get()),
+ static_cast<void*>(sb_error.get()), sstr.GetData());
}
return sb_error;
@@ -869,21 +881,32 @@ SBProcess::Signal (int signo)
sb_error.SetError (process_sp->Signal (signo));
}
else
- sb_error.SetErrorString ("SBProcess is invalid");
+ sb_error.SetErrorString ("SBProcess is invalid");
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
{
SBStream sstr;
sb_error.GetDescription (sstr);
- log->Printf ("SBProcess(%p)::Signal (signo=%i) => SBError (%p): %s",
- process_sp.get(),
- signo,
- sb_error.get(),
- sstr.GetData());
+ log->Printf ("SBProcess(%p)::Signal (signo=%i) => SBError (%p): %s",
+ static_cast<void*>(process_sp.get()), signo,
+ static_cast<void*>(sb_error.get()), sstr.GetData());
}
return sb_error;
}
+SBUnixSignals
+SBProcess::GetUnixSignals()
+{
+ SBUnixSignals sb_unix_signals;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ sb_unix_signals.SetSP(process_sp);
+ }
+
+ return sb_unix_signals;
+}
+
void
SBProcess::SendAsyncInterrupt ()
{
@@ -911,12 +934,9 @@ SBProcess::GetThreadByID (tid_t tid)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- {
log->Printf ("SBProcess(%p)::GetThreadByID (tid=0x%4.4" PRIx64 ") => SBThread (%p)",
- process_sp.get(),
- tid,
- thread_sp.get());
- }
+ static_cast<void*>(process_sp.get()), tid,
+ static_cast<void*>(thread_sp.get()));
return sb_thread;
}
@@ -938,12 +958,9 @@ SBProcess::GetThreadByIndexID (uint32_t index_id)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- {
- log->Printf ("SBProcess(%p)::GetThreadByID (tid=0x%x) => SBThread (%p)",
- process_sp.get(),
- index_id,
- thread_sp.get());
- }
+ log->Printf ("SBProcess(%p)::GetThreadByID (tid=0x%x) => SBThread (%p)",
+ static_cast<void*>(process_sp.get()), index_id,
+ static_cast<void*>(thread_sp.get()));
return sb_thread;
}
@@ -954,9 +971,10 @@ SBProcess::GetStateFromEvent (const SBEvent &event)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
StateType ret_val = Process::ProcessEventData::GetStateFromEvent (event.get());
-
+
if (log)
- log->Printf ("SBProcess::GetStateFromEvent (event.sp=%p) => %s", event.get(),
+ log->Printf ("SBProcess::GetStateFromEvent (event.sp=%p) => %s",
+ static_cast<void*>(event.get()),
lldb_private::StateAsCString (ret_val));
return ret_val;
@@ -1003,8 +1021,9 @@ SBProcess::GetBroadcaster () const
SBBroadcaster broadcaster(process_sp.get(), false);
if (log)
- log->Printf ("SBProcess(%p)::GetBroadcaster () => SBBroadcaster (%p)", process_sp.get(),
- broadcaster.get());
+ log->Printf ("SBProcess(%p)::GetBroadcaster () => SBBroadcaster (%p)",
+ static_cast<void*>(process_sp.get()),
+ static_cast<void*>(broadcaster.get()));
return broadcaster;
}
@@ -1025,15 +1044,11 @@ SBProcess::ReadMemory (addr_t addr, void *dst, size_t dst_len, SBError &sb_error
ProcessSP process_sp(GetSP());
if (log)
- {
log->Printf ("SBProcess(%p)::ReadMemory (addr=0x%" PRIx64 ", dst=%p, dst_len=%" PRIu64 ", SBError (%p))...",
- process_sp.get(),
- addr,
- dst,
- (uint64_t)dst_len,
- sb_error.get());
- }
-
+ static_cast<void*>(process_sp.get()), addr,
+ static_cast<void*>(dst), static_cast<uint64_t>(dst_len),
+ static_cast<void*>(sb_error.get()));
+
if (process_sp)
{
Process::StopLocker stop_locker;
@@ -1045,7 +1060,8 @@ SBProcess::ReadMemory (addr_t addr, void *dst, size_t dst_len, SBError &sb_error
else
{
if (log)
- log->Printf ("SBProcess(%p)::ReadMemory() => error: process is running", process_sp.get());
+ log->Printf ("SBProcess(%p)::ReadMemory() => error: process is running",
+ static_cast<void*>(process_sp.get()));
sb_error.SetErrorString("process is running");
}
}
@@ -1059,13 +1075,10 @@ SBProcess::ReadMemory (addr_t addr, void *dst, size_t dst_len, SBError &sb_error
SBStream sstr;
sb_error.GetDescription (sstr);
log->Printf ("SBProcess(%p)::ReadMemory (addr=0x%" PRIx64 ", dst=%p, dst_len=%" PRIu64 ", SBError (%p): %s) => %" PRIu64,
- process_sp.get(),
- addr,
- dst,
- (uint64_t)dst_len,
- sb_error.get(),
- sstr.GetData(),
- (uint64_t)bytes_read);
+ static_cast<void*>(process_sp.get()), addr,
+ static_cast<void*>(dst), static_cast<uint64_t>(dst_len),
+ static_cast<void*>(sb_error.get()), sstr.GetData(),
+ static_cast<uint64_t>(bytes_read));
}
return bytes_read;
@@ -1088,7 +1101,8 @@ SBProcess::ReadCStringFromMemory (addr_t addr, void *buf, size_t size, lldb::SBE
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBProcess(%p)::ReadCStringFromMemory() => error: process is running", process_sp.get());
+ log->Printf ("SBProcess(%p)::ReadCStringFromMemory() => error: process is running",
+ static_cast<void*>(process_sp.get()));
sb_error.SetErrorString("process is running");
}
}
@@ -1116,7 +1130,8 @@ SBProcess::ReadUnsignedFromMemory (addr_t addr, uint32_t byte_size, lldb::SBErro
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBProcess(%p)::ReadUnsignedFromMemory() => error: process is running", process_sp.get());
+ log->Printf ("SBProcess(%p)::ReadUnsignedFromMemory() => error: process is running",
+ static_cast<void*>(process_sp.get()));
sb_error.SetErrorString("process is running");
}
}
@@ -1144,7 +1159,8 @@ SBProcess::ReadPointerFromMemory (addr_t addr, lldb::SBError &sb_error)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBProcess(%p)::ReadPointerFromMemory() => error: process is running", process_sp.get());
+ log->Printf ("SBProcess(%p)::ReadPointerFromMemory() => error: process is running",
+ static_cast<void*>(process_sp.get()));
sb_error.SetErrorString("process is running");
}
}
@@ -1165,14 +1181,11 @@ SBProcess::WriteMemory (addr_t addr, const void *src, size_t src_len, SBError &s
ProcessSP process_sp(GetSP());
if (log)
- {
log->Printf ("SBProcess(%p)::WriteMemory (addr=0x%" PRIx64 ", src=%p, src_len=%" PRIu64 ", SBError (%p))...",
- process_sp.get(),
- addr,
- src,
- (uint64_t)src_len,
- sb_error.get());
- }
+ static_cast<void*>(process_sp.get()), addr,
+ static_cast<const void*>(src),
+ static_cast<uint64_t>(src_len),
+ static_cast<void*>(sb_error.get()));
if (process_sp)
{
@@ -1185,7 +1198,8 @@ SBProcess::WriteMemory (addr_t addr, const void *src, size_t src_len, SBError &s
else
{
if (log)
- log->Printf ("SBProcess(%p)::WriteMemory() => error: process is running", process_sp.get());
+ log->Printf ("SBProcess(%p)::WriteMemory() => error: process is running",
+ static_cast<void*>(process_sp.get()));
sb_error.SetErrorString("process is running");
}
}
@@ -1195,13 +1209,11 @@ SBProcess::WriteMemory (addr_t addr, const void *src, size_t src_len, SBError &s
SBStream sstr;
sb_error.GetDescription (sstr);
log->Printf ("SBProcess(%p)::WriteMemory (addr=0x%" PRIx64 ", src=%p, src_len=%" PRIu64 ", SBError (%p): %s) => %" PRIu64,
- process_sp.get(),
- addr,
- src,
- (uint64_t)src_len,
- sb_error.get(),
- sstr.GetData(),
- (uint64_t)bytes_written);
+ static_cast<void*>(process_sp.get()), addr,
+ static_cast<const void*>(src),
+ static_cast<uint64_t>(src_len),
+ static_cast<void*>(sb_error.get()), sstr.GetData(),
+ static_cast<uint64_t>(bytes_written));
}
return bytes_written;
@@ -1248,7 +1260,7 @@ SBProcess::GetNumSupportedHardwareWatchpoints (lldb::SBError &sb_error) const
sb_error.SetError(process_sp->GetWatchpointSupportInfo (num));
if (log)
log->Printf ("SBProcess(%p)::GetNumSupportedHardwareWatchpoints () => %u",
- process_sp.get(), num);
+ static_cast<void*>(process_sp.get()), num);
}
else
{
@@ -1273,13 +1285,14 @@ SBProcess::LoadImage (lldb::SBFileSpec &sb_image_spec, lldb::SBError &sb_error)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBProcess(%p)::LoadImage() => error: process is running", process_sp.get());
+ log->Printf ("SBProcess(%p)::LoadImage() => error: process is running",
+ static_cast<void*>(process_sp.get()));
sb_error.SetErrorString("process is running");
}
}
return LLDB_INVALID_IMAGE_TOKEN;
}
-
+
lldb::SBError
SBProcess::UnloadImage (uint32_t image_token)
{
@@ -1297,7 +1310,35 @@ SBProcess::UnloadImage (uint32_t image_token)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBProcess(%p)::UnloadImage() => error: process is running", process_sp.get());
+ log->Printf ("SBProcess(%p)::UnloadImage() => error: process is running",
+ static_cast<void*>(process_sp.get()));
+ sb_error.SetErrorString("process is running");
+ }
+ }
+ else
+ sb_error.SetErrorString("invalid process");
+ return sb_error;
+}
+
+lldb::SBError
+SBProcess::SendEventData (const char *event_data)
+{
+ lldb::SBError sb_error;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process_sp->GetRunLock()))
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ sb_error.SetError (process_sp->SendEventData (event_data));
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::SendEventData() => error: process is running",
+ static_cast<void*>(process_sp.get()));
sb_error.SetErrorString("process is running");
}
}
@@ -1334,7 +1375,8 @@ SBProcess::GetExtendedBacktraceTypeAtIndex (uint32_t idx)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf("SBProcess(%p)::GetExtendedBacktraceTypeAtIndex() => error: requested extended backtrace name out of bounds", process_sp.get());
+ log->Printf("SBProcess(%p)::GetExtendedBacktraceTypeAtIndex() => error: requested extended backtrace name out of bounds",
+ static_cast<void*>(process_sp.get()));
}
}
return NULL;
diff --git a/source/API/SBQueue.cpp b/source/API/SBQueue.cpp
index 8d67a48d6b81..b19ed72543c2 100644
--- a/source/API/SBQueue.cpp
+++ b/source/API/SBQueue.cpp
@@ -9,10 +9,14 @@
#include "lldb/lldb-python.h"
+#include <inttypes.h>
+
#include "lldb/API/SBQueue.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBThread.h"
+#include "lldb/API/SBQueueItem.h"
+
#include "lldb/Core/Log.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Queue.h"
@@ -96,7 +100,8 @@ namespace lldb_private
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBQueue(%p)::GetQueueID () => 0x%" PRIx64, this, result);
+ log->Printf ("SBQueue(%p)::GetQueueID () => 0x%" PRIx64,
+ static_cast<const void*>(this), result);
return result;
}
@@ -111,10 +116,11 @@ namespace lldb_private
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBQueueImpl(%p)::GetIndexID () => %d", this, result);
+ log->Printf ("SBQueueImpl(%p)::GetIndexID () => %d",
+ static_cast<const void*>(this), result);
return result;
}
-
+
const char *
GetName () const
{
@@ -124,14 +130,16 @@ namespace lldb_private
{
name = queue_sp->GetName();
}
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBQueueImpl(%p)::GetName () => %s", this, name ? name : "NULL");
-
+ log->Printf ("SBQueueImpl(%p)::GetName () => %s",
+ static_cast<const void*>(this),
+ name ? name : "NULL");
+
return name;
}
-
+
void
FetchThreads ()
{
@@ -158,7 +166,7 @@ namespace lldb_private
}
}
}
-
+
void
FetchItems ()
{
@@ -185,12 +193,12 @@ namespace lldb_private
}
}
}
-
+
uint32_t
GetNumThreads ()
{
uint32_t result = 0;
-
+
FetchThreads();
if (m_thread_list_fetched)
{
@@ -198,12 +206,12 @@ namespace lldb_private
}
return result;
}
-
+
lldb::SBThread
GetThreadAtIndex (uint32_t idx)
{
FetchThreads();
-
+
SBThread sb_thread;
QueueSP queue_sp = m_queue_wp.lock();
if (queue_sp && idx < m_threads.size())
@@ -220,21 +228,24 @@ namespace lldb_private
}
return sb_thread;
}
-
-
+
uint32_t
GetNumPendingItems ()
{
uint32_t result = 0;
- FetchItems();
-
- if (m_pending_items_fetched)
+
+ QueueSP queue_sp = m_queue_wp.lock();
+ if (m_pending_items_fetched == false && queue_sp)
+ {
+ result = queue_sp->GetNumPendingWorkItems();
+ }
+ else
{
result = m_pending_items.size();
}
return result;
}
-
+
lldb::SBQueueItem
GetPendingItemAtIndex (uint32_t idx)
{
@@ -246,7 +257,17 @@ namespace lldb_private
}
return result;
}
-
+
+ uint32_t
+ GetNumRunningItems ()
+ {
+ uint32_t result = 0;
+ QueueSP queue_sp = m_queue_wp.lock();
+ if (queue_sp)
+ result = queue_sp->GetNumRunningWorkItems();
+ return result;
+ }
+
lldb::SBProcess
GetProcess ()
{
@@ -259,6 +280,17 @@ namespace lldb_private
return result;
}
+ lldb::QueueKind
+ GetKind ()
+ {
+ lldb::QueueKind kind = eQueueKindUnknown;
+ QueueSP queue_sp = m_queue_wp.lock();
+ if (queue_sp)
+ kind = queue_sp->GetKind();
+
+ return kind;
+ }
+
private:
lldb::QueueWP m_queue_wp;
std::vector<lldb::ThreadWP> m_threads; // threads currently executing this queue's items
@@ -301,13 +333,21 @@ SBQueue::~SBQueue()
bool
SBQueue::IsValid() const
{
- return m_opaque_sp->IsValid();
+ bool is_valid = m_opaque_sp->IsValid ();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf("SBQueue(0x%" PRIx64 ")::IsValid() == %s", m_opaque_sp->GetQueueID(),
+ is_valid ? "true" : "false");
+ return is_valid;
}
void
SBQueue::Clear ()
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf("SBQueue(0x%" PRIx64 ")::Clear()", m_opaque_sp->GetQueueID());
m_opaque_sp->Clear();
}
@@ -321,48 +361,92 @@ SBQueue::SetQueue (const QueueSP& queue_sp)
lldb::queue_id_t
SBQueue::GetQueueID () const
{
- return m_opaque_sp->GetQueueID ();
+ lldb::queue_id_t qid = m_opaque_sp->GetQueueID ();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf("SBQueue(0x%" PRIx64 ")::GetQueueID() == 0x%" PRIx64, m_opaque_sp->GetQueueID(), (uint64_t) qid);
+ return qid;
}
uint32_t
SBQueue::GetIndexID () const
{
- return m_opaque_sp->GetIndexID ();
+ uint32_t index_id = m_opaque_sp->GetIndexID ();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf("SBQueue(0x%" PRIx64 ")::GetIndexID() == 0x%" PRIx32, m_opaque_sp->GetQueueID(), index_id);
+ return index_id;
}
const char *
SBQueue::GetName () const
{
- return m_opaque_sp->GetName ();
+ const char *name = m_opaque_sp->GetName ();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf("SBQueue(0x%" PRIx64 ")::GetName() == %s", m_opaque_sp->GetQueueID(),
+ name ? name : "");
+ return name;
}
uint32_t
SBQueue::GetNumThreads ()
{
- return m_opaque_sp->GetNumThreads ();
+ uint32_t numthreads = m_opaque_sp->GetNumThreads ();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf("SBQueue(0x%" PRIx64 ")::GetNumThreads() == %d", m_opaque_sp->GetQueueID(), numthreads);
+ return numthreads;
}
SBThread
SBQueue::GetThreadAtIndex (uint32_t idx)
{
- return m_opaque_sp->GetThreadAtIndex (idx);
+ SBThread th = m_opaque_sp->GetThreadAtIndex (idx);
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf("SBQueue(0x%" PRIx64 ")::GetThreadAtIndex(%d)", m_opaque_sp->GetQueueID(), idx);
+ return th;
}
uint32_t
SBQueue::GetNumPendingItems ()
{
- return m_opaque_sp->GetNumPendingItems ();
+ uint32_t pending_items = m_opaque_sp->GetNumPendingItems ();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf("SBQueue(0x%" PRIx64 ")::GetNumPendingItems() == %d", m_opaque_sp->GetQueueID(), pending_items);
+ return pending_items;
}
SBQueueItem
SBQueue::GetPendingItemAtIndex (uint32_t idx)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf("SBQueue(0x%" PRIx64 ")::GetPendingItemAtIndex(%d)", m_opaque_sp->GetQueueID(), idx);
return m_opaque_sp->GetPendingItemAtIndex (idx);
}
+uint32_t
+SBQueue::GetNumRunningItems ()
+{
+ uint32_t running_items = m_opaque_sp->GetNumRunningItems ();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf("SBQueue(0x%" PRIx64 ")::GetNumRunningItems() == %d", m_opaque_sp->GetQueueID(), running_items);
+ return running_items;
+}
+
SBProcess
SBQueue::GetProcess ()
{
return m_opaque_sp->GetProcess();
}
+
+lldb::QueueKind
+SBQueue::GetKind ()
+{
+ return m_opaque_sp->GetKind();
+}
diff --git a/source/API/SBQueueItem.cpp b/source/API/SBQueueItem.cpp
index 481d51e55426..6a1aa7bec61a 100644
--- a/source/API/SBQueueItem.cpp
+++ b/source/API/SBQueueItem.cpp
@@ -14,6 +14,8 @@
#include "lldb/API/SBQueueItem.h"
#include "lldb/API/SBThread.h"
#include "lldb/Core/Address.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/QueueItem.h"
#include "lldb/Target/Thread.h"
@@ -44,13 +46,23 @@ SBQueueItem::~SBQueueItem()
bool
SBQueueItem::IsValid() const
{
- return m_queue_item_sp.get() != NULL;
+ bool is_valid = m_queue_item_sp.get() != NULL;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf("SBQueueItem(%p)::IsValid() == %s",
+ static_cast<void*>(m_queue_item_sp.get()),
+ is_valid ? "true" : "false");
+ return is_valid;
}
void
SBQueueItem::Clear ()
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf("SBQueueItem(%p)::Clear()",
+ static_cast<void*>(m_queue_item_sp.get()));
m_queue_item_sp.reset();
}
@@ -66,10 +78,15 @@ lldb::QueueItemKind
SBQueueItem::GetKind () const
{
QueueItemKind result = eQueueItemKindUnknown;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (m_queue_item_sp)
{
result = m_queue_item_sp->GetKind ();
}
+ if (log)
+ log->Printf("SBQueueItem(%p)::GetKind() == %d",
+ static_cast<void*>(m_queue_item_sp.get()),
+ static_cast<int>(result));
return result;
}
@@ -86,10 +103,21 @@ SBAddress
SBQueueItem::GetAddress () const
{
SBAddress result;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (m_queue_item_sp)
{
result.SetAddress (&m_queue_item_sp->GetAddress());
}
+ if (log)
+ {
+ StreamString sstr;
+ const Address *addr = result.get();
+ if (addr)
+ addr->Dump (&sstr, NULL, Address::DumpStyleModuleWithFileAddress, Address::DumpStyleInvalid, 4);
+ log->Printf ("SBQueueItem(%p)::GetAddress() == SBAddress(%p): %s",
+ static_cast<void*>(m_queue_item_sp.get()),
+ static_cast<void*>(result.get()), sstr.GetData());
+ }
return result;
}
@@ -106,14 +134,34 @@ SBThread
SBQueueItem::GetExtendedBacktraceThread (const char *type)
{
SBThread result;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (m_queue_item_sp)
{
- ThreadSP thread_sp;
- ConstString type_const (type);
- thread_sp = m_queue_item_sp->GetExtendedBacktraceThread (type_const);
- if (thread_sp)
+ ProcessSP process_sp = m_queue_item_sp->GetProcessSP();
+ Process::StopLocker stop_locker;
+ if (process_sp && stop_locker.TryLock(&process_sp->GetRunLock()))
{
- result.SetThread (thread_sp);
+ ThreadSP thread_sp;
+ ConstString type_const (type);
+ thread_sp = m_queue_item_sp->GetExtendedBacktraceThread (type_const);
+ if (thread_sp)
+ {
+ // Save this in the Process' ExtendedThreadList so a strong pointer retains the
+ // object
+ process_sp->GetExtendedThreadList().AddThread (thread_sp);
+ result.SetThread (thread_sp);
+ if (log)
+ {
+ const char *queue_name = thread_sp->GetQueueName();
+ if (queue_name == NULL)
+ queue_name = "";
+ log->Printf ("SBQueueItem(%p)::GetExtendedBacktraceThread() = new extended Thread created (%p) with queue_id 0x%" PRIx64 " queue name '%s'",
+ static_cast<void*>(m_queue_item_sp.get()),
+ static_cast<void*>(thread_sp.get()),
+ static_cast<uint64_t>(thread_sp->GetQueueID()),
+ queue_name);
+ }
+ }
}
}
return result;
diff --git a/source/API/SBStream.cpp b/source/API/SBStream.cpp
index 531ab9f463ce..f5b5c08411c7 100644
--- a/source/API/SBStream.cpp
+++ b/source/API/SBStream.cpp
@@ -82,6 +82,8 @@ SBStream::RedirectToFile (const char *path, bool append)
uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
if (append)
open_options |= File::eOpenOptionAppend;
+ else
+ open_options |= File::eOpenOptionTruncate;
stream_file->GetFile().Open (path, open_options, lldb::eFilePermissionsFileDefault);
m_opaque_ap.reset (stream_file);
diff --git a/source/API/SBSymbol.cpp b/source/API/SBSymbol.cpp
index ef3d0764c963..12a3b317d501 100644
--- a/source/API/SBSymbol.cpp
+++ b/source/API/SBSymbol.cpp
@@ -67,7 +67,8 @@ SBSymbol::GetName() const
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBSymbol(%p)::GetName () => \"%s\"", m_opaque_ptr, name ? name : "");
+ log->Printf ("SBSymbol(%p)::GetName () => \"%s\"",
+ static_cast<void*>(m_opaque_ptr), name ? name : "");
return name;
}
@@ -79,7 +80,8 @@ SBSymbol::GetMangledName () const
name = m_opaque_ptr->GetMangled().GetMangledName().AsCString();
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBSymbol(%p)::GetMangledName () => \"%s\"", m_opaque_ptr, name ? name : "");
+ log->Printf ("SBSymbol(%p)::GetMangledName () => \"%s\"",
+ static_cast<void*>(m_opaque_ptr), name ? name : "");
return name;
}
diff --git a/source/API/SBSymbolContext.cpp b/source/API/SBSymbolContext.cpp
index 479b0f75bfe9..481fa1a1d1a2 100644
--- a/source/API/SBSymbolContext.cpp
+++ b/source/API/SBSymbolContext.cpp
@@ -101,8 +101,9 @@ SBSymbolContext::GetModule ()
{
SBStream sstr;
sb_module.GetDescription (sstr);
- log->Printf ("SBSymbolContext(%p)::GetModule () => SBModule(%p): %s",
- m_opaque_ap.get(), module_sp.get(), sstr.GetData());
+ log->Printf ("SBSymbolContext(%p)::GetModule () => SBModule(%p): %s",
+ static_cast<void*>(m_opaque_ap.get()),
+ static_cast<void*>(module_sp.get()), sstr.GetData());
}
return sb_module;
@@ -120,15 +121,16 @@ SBSymbolContext::GetFunction ()
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
Function *function = NULL;
-
+
if (m_opaque_ap.get())
function = m_opaque_ap->function;
SBFunction sb_function (function);
if (log)
- log->Printf ("SBSymbolContext(%p)::GetFunction () => SBFunction(%p)",
- m_opaque_ap.get(), function);
+ log->Printf ("SBSymbolContext(%p)::GetFunction () => SBFunction(%p)",
+ static_cast<void*>(m_opaque_ap.get()),
+ static_cast<void*>(function));
return sb_function;
}
@@ -150,8 +152,9 @@ SBSymbolContext::GetLineEntry ()
if (log)
{
- log->Printf ("SBSymbolContext(%p)::GetLineEntry () => SBLineEntry(%p)",
- m_opaque_ap.get(), sb_line_entry.get());
+ log->Printf ("SBSymbolContext(%p)::GetLineEntry () => SBLineEntry(%p)",
+ static_cast<void*>(m_opaque_ap.get()),
+ static_cast<void*>(sb_line_entry.get()));
}
return sb_line_entry;
@@ -163,19 +166,18 @@ SBSymbolContext::GetSymbol ()
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
Symbol *symbol = NULL;
-
+
if (m_opaque_ap.get())
symbol = m_opaque_ap->symbol;
SBSymbol sb_symbol (symbol);
if (log)
- {
- log->Printf ("SBSymbolContext(%p)::GetSymbol () => SBSymbol(%p)",
- m_opaque_ap.get(), symbol);
- }
+ log->Printf ("SBSymbolContext(%p)::GetSymbol () => SBSymbol(%p)",
+ static_cast<void*>(m_opaque_ap.get()),
+ static_cast<void*>(symbol));
- return sb_symbol;
+ return sb_symbol;
}
void
diff --git a/source/API/SBTarget.cpp b/source/API/SBTarget.cpp
index 224349c0bce6..3d5828c5fe00 100644
--- a/source/API/SBTarget.cpp
+++ b/source/API/SBTarget.cpp
@@ -120,6 +120,18 @@ SBLaunchInfo::SetGroupID (uint32_t gid)
m_opaque_sp->SetGroupID (gid);
}
+SBFileSpec
+SBLaunchInfo::GetExecutableFile ()
+{
+ return SBFileSpec (m_opaque_sp->GetExecutableFile());
+}
+
+void
+SBLaunchInfo::SetExecutableFile (SBFileSpec exe_file, bool add_as_first_arg)
+{
+ m_opaque_sp->SetExecutableFile(exe_file.ref(), add_as_first_arg);
+}
+
uint32_t
SBLaunchInfo::GetNumArguments ()
{
@@ -268,6 +280,29 @@ SBLaunchInfo::AddSuppressFileAction (int fd, bool read, bool write)
return m_opaque_sp->AppendSuppressFileAction(fd, read, write);
}
+void
+SBLaunchInfo::SetLaunchEventData (const char *data)
+{
+ m_opaque_sp->SetLaunchEventData (data);
+}
+
+const char *
+SBLaunchInfo::GetLaunchEventData () const
+{
+ return m_opaque_sp->GetLaunchEventData ();
+}
+
+void
+SBLaunchInfo::SetDetachOnError (bool enable)
+{
+ m_opaque_sp->SetDetachOnError (enable);
+}
+
+bool
+SBLaunchInfo::GetDetachOnError () const
+{
+ return m_opaque_sp->GetDetachOnError ();
+}
SBAttachInfo::SBAttachInfo () :
m_opaque_sp (new ProcessAttachInfo())
@@ -541,10 +576,9 @@ SBTarget::GetProcess ()
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- {
- log->Printf ("SBTarget(%p)::GetProcess () => SBProcess(%p)",
- target_sp.get(), process_sp.get());
- }
+ log->Printf ("SBTarget(%p)::GetProcess () => SBProcess(%p)",
+ static_cast<void*>(target_sp.get()),
+ static_cast<void*>(process_sp.get()));
return sb_process;
}
@@ -641,19 +675,15 @@ SBTarget::Launch
TargetSP target_sp(GetSP());
if (log)
- {
log->Printf ("SBTarget(%p)::Launch (argv=%p, envp=%p, stdin=%s, stdout=%s, stderr=%s, working-dir=%s, launch_flags=0x%x, stop_at_entry=%i, &error (%p))...",
- target_sp.get(),
- argv,
- envp,
- stdin_path ? stdin_path : "NULL",
- stdout_path ? stdout_path : "NULL",
- stderr_path ? stderr_path : "NULL",
+ static_cast<void*>(target_sp.get()),
+ static_cast<void*>(argv), static_cast<void*>(envp),
+ stdin_path ? stdin_path : "NULL",
+ stdout_path ? stdout_path : "NULL",
+ stderr_path ? stderr_path : "NULL",
working_directory ? working_directory : "NULL",
- launch_flags,
- stop_at_entry,
- error.get());
- }
+ launch_flags, stop_at_entry,
+ static_cast<void*>(error.get()));
if (target_sp)
{
@@ -667,17 +697,17 @@ SBTarget::Launch
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
@@ -694,7 +724,7 @@ SBTarget::Launch
launch_flags |= eLaunchFlagDisableSTDIO;
ProcessLaunchInfo launch_info (stdin_path, stdout_path, stderr_path, working_directory, launch_flags);
-
+
Module *exe_module = target_sp->GetExecutableModulePointer();
if (exe_module)
launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
@@ -717,10 +747,9 @@ SBTarget::Launch
log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API);
if (log)
- {
- log->Printf ("SBTarget(%p)::Launch (...) => SBProcess(%p)",
- target_sp.get(), sb_process.GetSP().get());
- }
+ log->Printf ("SBTarget(%p)::Launch (...) => SBProcess(%p)",
+ static_cast<void*>(target_sp.get()),
+ static_cast<void*>(sb_process.GetSP().get()));
return sb_process;
}
@@ -729,46 +758,48 @@ SBProcess
SBTarget::Launch (SBLaunchInfo &sb_launch_info, SBError& error)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
SBProcess sb_process;
TargetSP target_sp(GetSP());
-
+
if (log)
- {
- log->Printf ("SBTarget(%p)::Launch (launch_info, error)...", target_sp.get());
- }
-
+ log->Printf ("SBTarget(%p)::Launch (launch_info, error)...",
+ static_cast<void*>(target_sp.get()));
+
if (target_sp)
{
Mutex::Locker api_locker (target_sp->GetAPIMutex());
StateType state = eStateInvalid;
{
- ProcessSP 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;
- }
- }
+ ProcessSP 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;
+ }
+ }
}
lldb_private::ProcessLaunchInfo &launch_info = sb_launch_info.ref();
- Module *exe_module = target_sp->GetExecutableModulePointer();
- if (exe_module)
- launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
+ if (!launch_info.GetExecutableFile())
+ {
+ Module *exe_module = target_sp->GetExecutableModulePointer();
+ if (exe_module)
+ launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
+ }
const ArchSpec &arch_spec = target_sp->GetArchitecture();
if (arch_spec.IsValid())
launch_info.GetArchitecture () = arch_spec;
-
+
error.SetError (target_sp->Launch (target_sp->GetDebugger().GetListener(), launch_info));
sb_process.SetSP(target_sp->GetProcessSP());
}
@@ -776,14 +807,13 @@ SBTarget::Launch (SBLaunchInfo &sb_launch_info, SBError& error)
{
error.SetErrorString ("SBTarget is invalid");
}
-
+
log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API);
if (log)
- {
log->Printf ("SBTarget(%p)::Launch (...) => SBProcess(%p)",
- target_sp.get(), sb_process.GetSP().get());
- }
-
+ static_cast<void*>(target_sp.get()),
+ static_cast<void*>(sb_process.GetSP().get()));
+
return sb_process;
}
@@ -791,41 +821,39 @@ lldb::SBProcess
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)
- {
- log->Printf ("SBTarget(%p)::Attach (sb_attach_info, error)...", target_sp.get());
- }
-
+ log->Printf ("SBTarget(%p)::Attach (sb_attach_info, error)...",
+ static_cast<void*>(target_sp.get()));
+
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");
if (log)
- {
log->Printf ("SBTarget(%p)::Attach (...) => error %s",
- target_sp.get(), error.GetCString());
- }
+ 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);
@@ -850,7 +878,7 @@ SBTarget::Attach (SBAttachInfo &sb_attach_info, SBError& error)
if (log)
{
log->Printf ("SBTarget(%p)::Attach (...) => error %s",
- target_sp.get(), error.GetCString());
+ static_cast<void*>(target_sp.get()), error.GetCString());
}
return sb_process;
}
@@ -875,13 +903,12 @@ SBTarget::Attach (SBAttachInfo &sb_attach_info, SBError& error)
{
error.SetErrorString ("SBTarget is invalid");
}
-
+
if (log)
- {
log->Printf ("SBTarget(%p)::Attach (...) => SBProcess(%p)",
- target_sp.get(), process_sp.get());
- }
-
+ static_cast<void*>(target_sp.get()),
+ static_cast<void*>(process_sp.get()));
+
return sb_process;
}
@@ -913,10 +940,9 @@ SBTarget::AttachToProcessWithID
TargetSP target_sp(GetSP());
if (log)
- {
- log->Printf ("SBTarget(%p)::AttachToProcessWithID (listener, pid=%" PRId64 ", error)...", target_sp.get(), pid);
- }
-
+ log->Printf ("SBTarget(%p)::AttachToProcessWithID (listener, pid=%" PRId64 ", error)...",
+ static_cast<void*>(target_sp.get()), pid);
+
if (target_sp)
{
Mutex::Locker api_locker (target_sp->GetAPIMutex());
@@ -926,15 +952,15 @@ SBTarget::AttachToProcessWithID
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)
@@ -958,10 +984,10 @@ SBTarget::AttachToProcessWithID
if (process_sp)
{
sb_process.SetSP (process_sp);
-
+
ProcessAttachInfo attach_info;
attach_info.SetProcessID (pid);
-
+
PlatformSP platform_sp = target_sp->GetPlatform();
ProcessInstanceInfo instance_info;
if (platform_sp->GetProcessInfo(pid, instance_info))
@@ -986,12 +1012,11 @@ SBTarget::AttachToProcessWithID
{
error.SetErrorString ("SBTarget is invalid");
}
-
+
if (log)
- {
log->Printf ("SBTarget(%p)::AttachToProcessWithID (...) => SBProcess(%p)",
- target_sp.get(), process_sp.get());
- }
+ static_cast<void*>(target_sp.get()),
+ static_cast<void*>(process_sp.get()));
return sb_process;
}
@@ -1005,16 +1030,16 @@ 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)...", target_sp.get(), name, wait_for ? "true" : "false");
- }
-
+ log->Printf ("SBTarget(%p)::AttachToProcessWithName (listener, name=%s, wait_for=%s, error)...",
+ static_cast<void*>(target_sp.get()), name,
+ wait_for ? "true" : "false");
+
if (name && target_sp)
{
Mutex::Locker api_locker (target_sp->GetAPIMutex());
@@ -1024,17 +1049,17 @@ SBTarget::AttachToProcessWithName
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
@@ -1078,12 +1103,11 @@ SBTarget::AttachToProcessWithName
{
error.SetErrorString ("SBTarget is invalid");
}
-
+
if (log)
- {
log->Printf ("SBTarget(%p)::AttachToPorcessWithName (...) => SBProcess(%p)",
- target_sp.get(), process_sp.get());
- }
+ static_cast<void*>(target_sp.get()),
+ static_cast<void*>(process_sp.get()));
return sb_process;
}
@@ -1101,12 +1125,11 @@ SBTarget::ConnectRemote
SBProcess sb_process;
ProcessSP process_sp;
TargetSP target_sp(GetSP());
-
+
if (log)
- {
- log->Printf ("SBTarget(%p)::ConnectRemote (listener, url=%s, plugin_name=%s, error)...", target_sp.get(), url, plugin_name);
- }
-
+ log->Printf ("SBTarget(%p)::ConnectRemote (listener, url=%s, plugin_name=%s, error)...",
+ static_cast<void*>(target_sp.get()), url, plugin_name);
+
if (target_sp)
{
Mutex::Locker api_locker (target_sp->GetAPIMutex());
@@ -1114,8 +1137,7 @@ SBTarget::ConnectRemote
process_sp = target_sp->CreateProcess (listener.ref(), plugin_name, NULL);
else
process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), plugin_name, NULL);
-
-
+
if (process_sp)
{
sb_process.SetSP (process_sp);
@@ -1130,12 +1152,11 @@ SBTarget::ConnectRemote
{
error.SetErrorString ("SBTarget is invalid");
}
-
+
if (log)
- {
log->Printf ("SBTarget(%p)::ConnectRemote (...) => SBProcess(%p)",
- target_sp.get(), process_sp.get());
- }
+ static_cast<void*>(target_sp.get()),
+ static_cast<void*>(process_sp.get()));
return sb_process;
}
@@ -1155,8 +1176,9 @@ SBTarget::GetExecutable ()
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
{
- log->Printf ("SBTarget(%p)::GetExecutable () => SBFileSpec(%p)",
- target_sp.get(), exe_file_spec.get());
+ log->Printf ("SBTarget(%p)::GetExecutable () => SBFileSpec(%p)",
+ static_cast<void*>(target_sp.get()),
+ static_cast<const void*>(exe_file_spec.get()));
}
return exe_file_spec;
@@ -1258,7 +1280,7 @@ SBTarget::BreakpointCreateByLocation (const SBFileSpec &sb_file_spec,
if (target_sp && line != 0)
{
Mutex::Locker api_locker (target_sp->GetAPIMutex());
-
+
const LazyBool check_inlines = eLazyBoolCalculate;
const LazyBool skip_prologue = eLazyBoolCalculate;
const bool internal = false;
@@ -1272,12 +1294,9 @@ SBTarget::BreakpointCreateByLocation (const SBFileSpec &sb_file_spec,
sb_bp.GetDescription (sstr);
char path[PATH_MAX];
sb_file_spec->GetPath (path, sizeof(path));
- log->Printf ("SBTarget(%p)::BreakpointCreateByLocation ( %s:%u ) => SBBreakpoint(%p): %s",
- target_sp.get(),
- path,
- line,
- sb_bp.get(),
- sstr.GetData());
+ log->Printf ("SBTarget(%p)::BreakpointCreateByLocation ( %s:%u ) => SBBreakpoint(%p): %s",
+ static_cast<void*>(target_sp.get()), path, line,
+ static_cast<void*>(sb_bp.get()), sstr.GetData());
}
return sb_bp;
@@ -1294,7 +1313,7 @@ SBTarget::BreakpointCreateByName (const char *symbol_name,
if (target_sp.get())
{
Mutex::Locker api_locker (target_sp->GetAPIMutex());
-
+
const bool internal = false;
const bool hardware = false;
const LazyBool skip_prologue = eLazyBoolCalculate;
@@ -1309,12 +1328,11 @@ SBTarget::BreakpointCreateByName (const char *symbol_name,
*sb_bp = target_sp->CreateBreakpoint (NULL, NULL, symbol_name, eFunctionNameTypeAuto, skip_prologue, internal, hardware);
}
}
-
+
if (log)
- {
- log->Printf ("SBTarget(%p)::BreakpointCreateByName (symbol=\"%s\", module=\"%s\") => SBBreakpoint(%p)",
- target_sp.get(), symbol_name, module_name, sb_bp.get());
- }
+ log->Printf ("SBTarget(%p)::BreakpointCreateByName (symbol=\"%s\", module=\"%s\") => SBBreakpoint(%p)",
+ static_cast<void*>(target_sp.get()), symbol_name,
+ module_name, static_cast<void*>(sb_bp.get()));
return sb_bp;
}
@@ -1352,12 +1370,11 @@ SBTarget::BreakpointCreateByName (const char *symbol_name,
internal,
hardware);
}
-
+
if (log)
- {
- log->Printf ("SBTarget(%p)::BreakpointCreateByName (symbol=\"%s\", name_type: %d) => SBBreakpoint(%p)",
- target_sp.get(), symbol_name, name_type_mask, sb_bp.get());
- }
+ log->Printf ("SBTarget(%p)::BreakpointCreateByName (symbol=\"%s\", name_type: %d) => SBBreakpoint(%p)",
+ static_cast<void*>(target_sp.get()), symbol_name,
+ name_type_mask, static_cast<void*>(sb_bp.get()));
return sb_bp;
}
@@ -1388,10 +1405,11 @@ SBTarget::BreakpointCreateByNames (const char *symbol_names[],
internal,
hardware);
}
-
+
if (log)
{
- log->Printf ("SBTarget(%p)::BreakpointCreateByName (symbols={", target_sp.get());
+ log->Printf ("SBTarget(%p)::BreakpointCreateByName (symbols={",
+ static_cast<void*>(target_sp.get()));
for (uint32_t i = 0 ; i < num_names; i++)
{
char sep;
@@ -1403,9 +1421,9 @@ SBTarget::BreakpointCreateByNames (const char *symbol_names[],
log->Printf ("\"%s\"%c ", symbol_names[i], sep);
else
log->Printf ("\"<NULL>\"%c ", sep);
-
}
- log->Printf ("name_type: %d) => SBBreakpoint(%p)", name_type_mask, sb_bp.get());
+ log->Printf ("name_type: %d) => SBBreakpoint(%p)", name_type_mask,
+ static_cast<void*>(sb_bp.get()));
}
return sb_bp;
@@ -1426,12 +1444,12 @@ SBTarget::BreakpointCreateByRegex (const char *symbol_name_regex,
const bool internal = false;
const bool hardware = false;
const LazyBool skip_prologue = eLazyBoolCalculate;
-
+
if (module_name && module_name[0])
{
FileSpecList module_spec_list;
module_spec_list.Append (FileSpec (module_name, false));
-
+
*sb_bp = target_sp->CreateFuncRegexBreakpoint (&module_spec_list, NULL, regexp, skip_prologue, internal, hardware);
}
else
@@ -1441,10 +1459,9 @@ SBTarget::BreakpointCreateByRegex (const char *symbol_name_regex,
}
if (log)
- {
- log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (symbol_regex=\"%s\", module_name=\"%s\") => SBBreakpoint(%p)",
- target_sp.get(), symbol_name_regex, module_name, sb_bp.get());
- }
+ log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (symbol_regex=\"%s\", module_name=\"%s\") => SBBreakpoint(%p)",
+ static_cast<void*>(target_sp.get()), symbol_name_regex,
+ module_name, static_cast<void*>(sb_bp.get()));
return sb_bp;
}
@@ -1465,15 +1482,14 @@ SBTarget::BreakpointCreateByRegex (const char *symbol_name_regex,
const bool internal = false;
const bool hardware = false;
const LazyBool skip_prologue = eLazyBoolCalculate;
-
+
*sb_bp = target_sp->CreateFuncRegexBreakpoint (module_list.get(), comp_unit_list.get(), regexp, skip_prologue, internal, hardware);
}
if (log)
- {
- log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (symbol_regex=\"%s\") => SBBreakpoint(%p)",
- target_sp.get(), symbol_name_regex, sb_bp.get());
- }
+ log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (symbol_regex=\"%s\") => SBBreakpoint(%p)",
+ static_cast<void*>(target_sp.get()), symbol_name_regex,
+ static_cast<void*>(sb_bp.get()));
return sb_bp;
}
@@ -1491,11 +1507,12 @@ SBTarget::BreakpointCreateByAddress (addr_t address)
const bool hardware = false;
*sb_bp = target_sp->CreateBreakpoint (address, false, hardware);
}
-
+
if (log)
- {
- log->Printf ("SBTarget(%p)::BreakpointCreateByAddress (address=%" PRIu64 ") => SBBreakpoint(%p)", target_sp.get(), (uint64_t) address, sb_bp.get());
- }
+ log->Printf ("SBTarget(%p)::BreakpointCreateByAddress (address=%" PRIu64 ") => SBBreakpoint(%p)",
+ static_cast<void*>(target_sp.get()),
+ static_cast<uint64_t>(address),
+ static_cast<void*>(sb_bp.get()));
return sb_bp;
}
@@ -1516,12 +1533,12 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
FileSpecList source_file_spec_list;
const bool hardware = false;
source_file_spec_list.Append (source_file.ref());
-
+
if (module_name && module_name[0])
{
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);
}
else
@@ -1534,8 +1551,9 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
{
char path[PATH_MAX];
source_file->GetPath (path, sizeof(path));
- log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (source_regex=\"%s\", file=\"%s\", module_name=\"%s\") => SBBreakpoint(%p)",
- target_sp.get(), source_regex, path, module_name, sb_bp.get());
+ log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (source_regex=\"%s\", file=\"%s\", module_name=\"%s\") => SBBreakpoint(%p)",
+ static_cast<void*>(target_sp.get()), source_regex, path,
+ module_name, static_cast<void*>(sb_bp.get()));
}
return sb_bp;
@@ -1559,10 +1577,9 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
}
if (log)
- {
- log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (source_regex=\"%s\") => SBBreakpoint(%p)",
- target_sp.get(), source_regex, sb_bp.get());
- }
+ log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (source_regex=\"%s\") => SBBreakpoint(%p)",
+ static_cast<void*>(target_sp.get()), source_regex,
+ static_cast<void*>(sb_bp.get()));
return sb_bp;
}
@@ -1584,14 +1601,11 @@ SBTarget::BreakpointCreateForException (lldb::LanguageType language,
}
if (log)
- {
- log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (Language: %s, catch: %s throw: %s) => SBBreakpoint(%p)",
- target_sp.get(),
+ log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (Language: %s, catch: %s throw: %s) => SBBreakpoint(%p)",
+ static_cast<void*>(target_sp.get()),
LanguageRuntime::GetNameForLanguageType(language),
- catch_bp ? "on" : "off",
- throw_bp ? "on" : "off",
- sb_bp.get());
- }
+ catch_bp ? "on" : "off", throw_bp ? "on" : "off",
+ static_cast<void*>(sb_bp.get()));
return sb_bp;
}
@@ -1635,9 +1649,9 @@ SBTarget::BreakpointDelete (break_id_t bp_id)
}
if (log)
- {
- log->Printf ("SBTarget(%p)::BreakpointDelete (bp_id=%d) => %i", target_sp.get(), (uint32_t) bp_id, result);
- }
+ log->Printf ("SBTarget(%p)::BreakpointDelete (bp_id=%d) => %i",
+ static_cast<void*>(target_sp.get()),
+ static_cast<uint32_t>(bp_id), result);
return result;
}
@@ -1656,10 +1670,10 @@ SBTarget::FindBreakpointByID (break_id_t bp_id)
}
if (log)
- {
- log->Printf ("SBTarget(%p)::FindBreakpointByID (bp_id=%d) => SBBreakpoint(%p)",
- target_sp.get(), (uint32_t) bp_id, sb_breakpoint.get());
- }
+ log->Printf ("SBTarget(%p)::FindBreakpointByID (bp_id=%d) => SBBreakpoint(%p)",
+ static_cast<void*>(target_sp.get()),
+ static_cast<uint32_t>(bp_id),
+ static_cast<void*>(sb_breakpoint.get()));
return sb_breakpoint;
}
@@ -1744,9 +1758,9 @@ SBTarget::DeleteWatchpoint (watch_id_t wp_id)
}
if (log)
- {
- log->Printf ("SBTarget(%p)::WatchpointDelete (wp_id=%d) => %i", target_sp.get(), (uint32_t) wp_id, result);
- }
+ log->Printf ("SBTarget(%p)::WatchpointDelete (wp_id=%d) => %i",
+ static_cast<void*>(target_sp.get()),
+ static_cast<uint32_t>(wp_id), result);
return result;
}
@@ -1769,10 +1783,10 @@ SBTarget::FindWatchpointByID (lldb::watch_id_t wp_id)
}
if (log)
- {
- log->Printf ("SBTarget(%p)::FindWatchpointByID (bp_id=%d) => SBWatchpoint(%p)",
- target_sp.get(), (uint32_t) wp_id, watchpoint_sp.get());
- }
+ log->Printf ("SBTarget(%p)::FindWatchpointByID (bp_id=%d) => SBWatchpoint(%p)",
+ static_cast<void*>(target_sp.get()),
+ static_cast<uint32_t>(wp_id),
+ static_cast<void*>(watchpoint_sp.get()));
return sb_watchpoint;
}
@@ -1781,7 +1795,7 @@ lldb::SBWatchpoint
SBTarget::WatchAddress (lldb::addr_t addr, size_t size, bool read, bool write, SBError &error)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
SBWatchpoint sb_watchpoint;
lldb::WatchpointSP watchpoint_sp;
TargetSP target_sp(GetSP());
@@ -1798,7 +1812,7 @@ SBTarget::WatchAddress (lldb::addr_t addr, size_t size, bool read, bool write, S
error.SetErrorString("Can't create a watchpoint that is neither read nor write.");
return sb_watchpoint;
}
-
+
// Target::CreateWatchpoint() is thread safe.
Error cw_error;
// This API doesn't take in a type, so we can't figure out what it is.
@@ -1807,13 +1821,13 @@ SBTarget::WatchAddress (lldb::addr_t addr, size_t size, bool read, bool write, S
error.SetError(cw_error);
sb_watchpoint.SetSP (watchpoint_sp);
}
-
+
if (log)
- {
log->Printf ("SBTarget(%p)::WatchAddress (addr=0x%" PRIx64 ", 0x%u) => SBWatchpoint(%p)",
- target_sp.get(), addr, (uint32_t) size, watchpoint_sp.get());
- }
-
+ static_cast<void*>(target_sp.get()), addr,
+ static_cast<uint32_t>(size),
+ static_cast<void*>(watchpoint_sp.get()));
+
return sb_watchpoint;
}
@@ -1860,7 +1874,7 @@ SBTarget::CreateValueFromAddress (const char *name, SBAddress addr, SBType type)
if (pointer_ast_type)
{
lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&address,sizeof(lldb::addr_t)));
-
+
ExecutionContext exe_ctx (ExecutionContextRef(ExecutionContext(m_opaque_sp.get(),false)));
ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
pointer_ast_type,
@@ -1868,7 +1882,7 @@ SBTarget::CreateValueFromAddress (const char *name, SBAddress addr, SBType type)
buffer,
exe_ctx.GetByteOrder(),
exe_ctx.GetAddressByteSize()));
-
+
if (ptr_result_valobj_sp)
{
ptr_result_valobj_sp->GetValue().SetValueType(Value::eValueTypeLoadAddress);
@@ -1884,9 +1898,12 @@ SBTarget::CreateValueFromAddress (const char *name, SBAddress addr, SBType type)
if (log)
{
if (new_value_sp)
- log->Printf ("SBTarget(%p)::CreateValueFromAddress => \"%s\"", m_opaque_sp.get(), new_value_sp->GetName().AsCString());
+ log->Printf ("SBTarget(%p)::CreateValueFromAddress => \"%s\"",
+ static_cast<void*>(m_opaque_sp.get()),
+ new_value_sp->GetName().AsCString());
else
- log->Printf ("SBTarget(%p)::CreateValueFromAddress => NULL", m_opaque_sp.get());
+ log->Printf ("SBTarget(%p)::CreateValueFromAddress => NULL",
+ static_cast<void*>(m_opaque_sp.get()));
}
return sb_value;
}
@@ -1981,7 +1998,8 @@ SBTarget::GetNumModules () const
}
if (log)
- log->Printf ("SBTarget(%p)::GetNumModules () => %d", target_sp.get(), num);
+ log->Printf ("SBTarget(%p)::GetNumModules () => %d",
+ static_cast<void*>(target_sp.get()), num);
return num;
}
@@ -1992,7 +2010,8 @@ SBTarget::Clear ()
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBTarget(%p)::Clear ()", m_opaque_sp.get());
+ log->Printf ("SBTarget(%p)::Clear ()",
+ static_cast<void*>(m_opaque_sp.get()));
m_opaque_sp.reset();
}
@@ -2063,10 +2082,9 @@ SBTarget::GetModuleAtIndex (uint32_t idx)
}
if (log)
- {
- log->Printf ("SBTarget(%p)::GetModuleAtIndex (idx=%d) => SBModule(%p)",
- target_sp.get(), idx, module_sp.get());
- }
+ log->Printf ("SBTarget(%p)::GetModuleAtIndex (idx=%d) => SBModule(%p)",
+ static_cast<void*>(target_sp.get()), idx,
+ static_cast<void*>(module_sp.get()));
return sb_module;
}
@@ -2088,10 +2106,11 @@ SBTarget::GetBroadcaster () const
TargetSP target_sp(GetSP());
SBBroadcaster broadcaster(target_sp.get(), false);
-
+
if (log)
- log->Printf ("SBTarget(%p)::GetBroadcaster () => SBBroadcaster(%p)",
- target_sp.get(), broadcaster.get());
+ log->Printf ("SBTarget(%p)::GetBroadcaster () => SBBroadcaster(%p)",
+ static_cast<void*>(target_sp.get()),
+ static_cast<void*>(broadcaster.get()));
return broadcaster;
}
@@ -2432,10 +2451,6 @@ SBTarget::SetSectionLoadAddress (lldb::SBSection section,
else
{
ProcessSP process_sp (target_sp->GetProcessSP());
- uint32_t stop_id = 0;
- if (process_sp)
- stop_id = process_sp->GetStopID();
-
if (target_sp->SetSectionLoadAddress (section_sp, section_base_addr))
{
// Flush info in the process (stack frames, etc)
@@ -2468,10 +2483,6 @@ SBTarget::ClearSectionLoadAddress (lldb::SBSection section)
else
{
ProcessSP process_sp (target_sp->GetProcessSP());
- uint32_t stop_id = 0;
- if (process_sp)
- stop_id = process_sp->GetStopID();
-
if (target_sp->SetSectionUnloaded (section.GetSP()))
{
// Flush info in the process (stack frames, etc)
@@ -2547,9 +2558,6 @@ SBTarget::ClearModuleLoadAddress (lldb::SBModule module)
if (section_list)
{
ProcessSP process_sp (target_sp->GetProcessSP());
- uint32_t stop_id = 0;
- if (process_sp)
- stop_id = process_sp->GetStopID();
bool changed = false;
const size_t num_sections = section_list->GetSize();
@@ -2557,7 +2565,7 @@ SBTarget::ClearModuleLoadAddress (lldb::SBModule module)
{
SectionSP section_sp (section_list->GetSectionAtIndex(sect_idx));
if (section_sp)
- changed |= target_sp->SetSectionUnloaded (section_sp) > 0;
+ changed |= target_sp->SetSectionUnloaded (section_sp);
}
if (changed)
{
@@ -2619,7 +2627,7 @@ SBTarget::EvaluateExpression (const char *expr, const SBExpressionOptions &optio
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
Log * expr_log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
SBValue expr_result;
- ExecutionResults exe_results = eExecutionSetupError;
+ ExpressionResults exe_results = eExpressionSetupError;
ValueObjectSP expr_value_sp;
TargetSP target_sp(GetSP());
StackFrame *frame = NULL;
@@ -2631,16 +2639,16 @@ SBTarget::EvaluateExpression (const char *expr, const SBExpressionOptions &optio
log->Printf ("SBTarget::EvaluateExpression called with an empty expression");
return expr_result;
}
-
+
Mutex::Locker api_locker (target_sp->GetAPIMutex());
ExecutionContext exe_ctx (m_opaque_sp.get());
-
+
if (log)
log->Printf ("SBTarget()::EvaluateExpression (expr=\"%s\")...", expr);
-
+
frame = exe_ctx.GetFramePtr();
Target *target = exe_ctx.GetTargetPtr();
-
+
if (target)
{
#ifdef LLDB_CONFIGURATION_DEBUG
@@ -2669,17 +2677,14 @@ SBTarget::EvaluateExpression (const char *expr, const SBExpressionOptions &optio
#ifndef LLDB_DISABLE_PYTHON
if (expr_log)
expr_log->Printf("** [SBTarget::EvaluateExpression] Expression result is %s, summary %s **",
- expr_result.GetValue(),
- expr_result.GetSummary());
-
+ expr_result.GetValue(), expr_result.GetSummary());
+
if (log)
log->Printf ("SBTarget(%p)::EvaluateExpression (expr=\"%s\") => SBValue(%p) (execution result=%d)",
- frame,
- expr,
- expr_value_sp.get(),
- exe_results);
+ static_cast<void*>(frame), expr,
+ static_cast<void*>(expr_value_sp.get()), exe_results);
#endif
-
+
return expr_result;
}
diff --git a/source/API/SBThread.cpp b/source/API/SBThread.cpp
index 4170d5b230bb..a0bfa4313535 100644
--- a/source/API/SBThread.cpp
+++ b/source/API/SBThread.cpp
@@ -19,10 +19,12 @@
#include "lldb/Core/State.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/Queue.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Target/StopInfo.h"
@@ -88,6 +90,42 @@ SBThread::~SBThread()
{
}
+lldb::SBQueue
+SBThread::GetQueue () const
+{
+ SBQueue sb_queue;
+ QueueSP queue_sp;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ queue_sp = exe_ctx.GetThreadPtr()->GetQueue();
+ if (queue_sp)
+ {
+ sb_queue.SetQueue (queue_sp);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::GetQueueKind() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
+ }
+ }
+
+ if (log)
+ log->Printf ("SBThread(%p)::GetQueueKind () => SBQueue(%p)",
+ static_cast<void*>(exe_ctx.GetThreadPtr()), static_cast<void*>(queue_sp.get()));
+
+ return sb_queue;
+}
+
+
bool
SBThread::IsValid() const
{
@@ -120,12 +158,14 @@ SBThread::GetStopReason()
else
{
if (log)
- log->Printf ("SBThread(%p)::GetStopReason() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::GetStopReason() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
if (log)
- log->Printf ("SBThread(%p)::GetStopReason () => %s", exe_ctx.GetThreadPtr(),
+ log->Printf ("SBThread(%p)::GetStopReason () => %s",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
Thread::StopReasonAsCString (reason));
return reason;
@@ -183,7 +223,8 @@ SBThread::GetStopReasonDataCount ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBThread(%p)::GetStopReasonDataCount() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::GetStopReasonDataCount() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
return 0;
@@ -226,7 +267,7 @@ SBThread::GetStopReasonDataAtIndex (uint32_t idx)
BreakpointLocationSP bp_loc_sp (bp_site_sp->GetOwnerAtIndex (bp_index));
if (bp_loc_sp)
{
- if (bp_index & 1)
+ if (idx & 1)
{
// Odd idx, return the breakpoint location ID
return bp_loc_sp->GetID();
@@ -257,7 +298,8 @@ SBThread::GetStopReasonDataAtIndex (uint32_t idx)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBThread(%p)::GetStopReasonDataAtIndex() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::GetStopReasonDataAtIndex() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
return 0;
@@ -284,8 +326,9 @@ SBThread::GetStopDescription (char *dst, size_t dst_len)
if (stop_desc)
{
if (log)
- log->Printf ("SBThread(%p)::GetStopDescription (dst, dst_len) => \"%s\"",
- exe_ctx.GetThreadPtr(), stop_desc);
+ log->Printf ("SBThread(%p)::GetStopDescription (dst, dst_len) => \"%s\"",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ stop_desc);
if (dst)
return ::snprintf (dst, dst_len, "%s", stop_desc);
else
@@ -362,19 +405,20 @@ SBThread::GetStopDescription (char *dst, size_t dst_len)
default:
break;
}
-
+
if (stop_desc && stop_desc[0])
{
if (log)
- log->Printf ("SBThread(%p)::GetStopDescription (dst, dst_len) => '%s'",
- exe_ctx.GetThreadPtr(), stop_desc);
+ log->Printf ("SBThread(%p)::GetStopDescription (dst, dst_len) => '%s'",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ stop_desc);
if (dst)
return ::snprintf (dst, dst_len, "%s", stop_desc) + 1; // Include the NULL byte
if (stop_desc_len == 0)
stop_desc_len = ::strlen (stop_desc) + 1; // Include the NULL byte
-
+
return stop_desc_len;
}
}
@@ -384,7 +428,8 @@ SBThread::GetStopDescription (char *dst, size_t dst_len)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBThread(%p)::GetStopDescription() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::GetStopDescription() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
if (dst)
@@ -414,16 +459,18 @@ SBThread::GetStopReturnValue ()
else
{
if (log)
- log->Printf ("SBThread(%p)::GetStopReturnValue() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::GetStopReturnValue() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
-
+
if (log)
- log->Printf ("SBThread(%p)::GetStopReturnValue () => %s", exe_ctx.GetThreadPtr(),
- return_valobj_sp.get()
- ? return_valobj_sp->GetValueAsCString()
- : "<no return value>");
-
+ log->Printf ("SBThread(%p)::GetStopReturnValue () => %s",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ return_valobj_sp.get()
+ ? return_valobj_sp->GetValueAsCString()
+ : "<no return value>");
+
return SBValue (return_valobj_sp);
}
@@ -469,12 +516,15 @@ SBThread::GetName () const
else
{
if (log)
- log->Printf ("SBThread(%p)::GetName() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::GetName() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
-
+
if (log)
- log->Printf ("SBThread(%p)::GetName () => %s", exe_ctx.GetThreadPtr(), name ? name : "NULL");
+ log->Printf ("SBThread(%p)::GetName () => %s",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ name ? name : "NULL");
return name;
}
@@ -497,12 +547,15 @@ SBThread::GetQueueName () const
else
{
if (log)
- log->Printf ("SBThread(%p)::GetQueueName() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::GetQueueName() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
-
+
if (log)
- log->Printf ("SBThread(%p)::GetQueueName () => %s", exe_ctx.GetThreadPtr(), name ? name : "NULL");
+ log->Printf ("SBThread(%p)::GetQueueName () => %s",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ name ? name : "NULL");
return name;
}
@@ -525,16 +578,86 @@ SBThread::GetQueueID () const
else
{
if (log)
- log->Printf ("SBThread(%p)::GetQueueID() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::GetQueueID() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
-
+
if (log)
- log->Printf ("SBThread(%p)::GetQueueID () => 0x%" PRIx64, exe_ctx.GetThreadPtr(), id);
+ log->Printf ("SBThread(%p)::GetQueueID () => 0x%" PRIx64,
+ static_cast<void*>(exe_ctx.GetThreadPtr()), id);
return id;
}
+bool
+SBThread::GetInfoItemByPathAsString (const char *path, SBStream &strm)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ bool success = false;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ Thread *thread = exe_ctx.GetThreadPtr();
+ StructuredData::ObjectSP info_root_sp = thread->GetExtendedInfo();
+ if (info_root_sp)
+ {
+ StructuredData::ObjectSP node = info_root_sp->GetObjectForDotSeparatedPath (path);
+ if (node)
+ {
+ if (node->GetType() == StructuredData::Type::eTypeString)
+ {
+ strm.Printf ("%s", node->GetAsString()->GetValue().c_str());
+ success = true;
+ }
+ if (node->GetType() == StructuredData::Type::eTypeInteger)
+ {
+ strm.Printf ("0x%" PRIx64, node->GetAsInteger()->GetValue());
+ success = true;
+ }
+ if (node->GetType() == StructuredData::Type::eTypeFloat)
+ {
+ strm.Printf ("0x%f", node->GetAsFloat()->GetValue());
+ success = true;
+ }
+ if (node->GetType() == StructuredData::Type::eTypeBoolean)
+ {
+ if (node->GetAsBoolean()->GetValue() == true)
+ strm.Printf ("true");
+ else
+ strm.Printf ("false");
+ success = true;
+ }
+ if (node->GetType() == StructuredData::Type::eTypeNull)
+ {
+ strm.Printf ("null");
+ success = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::GetInfoItemByPathAsString() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
+ }
+ }
+
+ if (log)
+ log->Printf ("SBThread(%p)::GetInfoItemByPathAsString () => %s",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ strm.GetData());
+
+ return success;
+}
+
+
SBError
SBThread::ResumeNewPlan (ExecutionContext &exe_ctx, ThreadPlan *new_plan)
{
@@ -587,9 +710,10 @@ SBThread::StepOver (lldb::RunMode stop_other_threads)
if (log)
- log->Printf ("SBThread(%p)::StepOver (stop_other_threads='%s')", exe_ctx.GetThreadPtr(),
+ log->Printf ("SBThread(%p)::StepOver (stop_other_threads='%s')",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
Thread::RunModeAsCString (stop_other_threads));
-
+
if (exe_ctx.HasThreadScope())
{
Thread *thread = exe_ctx.GetThreadPtr();
@@ -601,17 +725,19 @@ SBThread::StepOver (lldb::RunMode stop_other_threads)
{
if (frame_sp->HasDebugInformation ())
{
+ const LazyBool avoid_no_debug = eLazyBoolCalculate;
SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
new_plan_sp = thread->QueueThreadPlanForStepOverRange (abort_other_plans,
sc.line_entry.range,
sc,
- stop_other_threads);
+ stop_other_threads,
+ avoid_no_debug);
}
else
{
new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (true,
- abort_other_plans,
- stop_other_threads);
+ abort_other_plans,
+ stop_other_threads);
}
}
@@ -636,10 +762,10 @@ SBThread::StepInto (const char *target_name, lldb::RunMode stop_other_threads)
if (log)
log->Printf ("SBThread(%p)::StepInto (target_name='%s', stop_other_threads='%s')",
- exe_ctx.GetThreadPtr(),
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
target_name? target_name: "<NULL>",
Thread::RunModeAsCString (stop_other_threads));
-
+
if (exe_ctx.HasThreadScope())
{
bool abort_other_plans = false;
@@ -650,22 +776,24 @@ SBThread::StepInto (const char *target_name, lldb::RunMode stop_other_threads)
if (frame_sp && frame_sp->HasDebugInformation ())
{
- bool avoid_code_without_debug_info = true;
+ const LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate;
+ const LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate;
SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
new_plan_sp = thread->QueueThreadPlanForStepInRange (abort_other_plans,
sc.line_entry.range,
sc,
target_name,
stop_other_threads,
- avoid_code_without_debug_info);
+ step_in_avoids_code_without_debug_info,
+ step_out_avoids_code_without_debug_info);
}
else
{
new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (false,
- abort_other_plans,
- stop_other_threads);
+ abort_other_plans,
+ stop_other_threads);
}
-
+
// This returns an error, we should use it!
ResumeNewPlan (exe_ctx, new_plan_sp.get());
}
@@ -681,8 +809,9 @@ SBThread::StepOut ()
if (log)
- log->Printf ("SBThread(%p)::StepOut ()", exe_ctx.GetThreadPtr());
-
+ log->Printf ("SBThread(%p)::StepOut ()",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
+
if (exe_ctx.HasThreadScope())
{
bool abort_other_plans = false;
@@ -690,14 +819,16 @@ SBThread::StepOut ()
Thread *thread = exe_ctx.GetThreadPtr();
+ const LazyBool avoid_no_debug = eLazyBoolCalculate;
ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut (abort_other_plans,
- NULL,
- false,
- stop_other_threads,
- eVoteYes,
- eVoteNoOpinion,
- 0));
-
+ NULL,
+ false,
+ stop_other_threads,
+ eVoteYes,
+ eVoteNoOpinion,
+ 0,
+ avoid_no_debug));
+
// This returns an error, we should use it!
ResumeNewPlan (exe_ctx, new_plan_sp.get());
}
@@ -716,7 +847,10 @@ SBThread::StepOutOfFrame (lldb::SBFrame &sb_frame)
{
SBStream frame_desc_strm;
sb_frame.GetDescription (frame_desc_strm);
- log->Printf ("SBThread(%p)::StepOutOfFrame (frame = SBFrame(%p): %s)", exe_ctx.GetThreadPtr(), frame_sp.get(), frame_desc_strm.GetData());
+ log->Printf ("SBThread(%p)::StepOutOfFrame (frame = SBFrame(%p): %s)",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ static_cast<void*>(frame_sp.get()),
+ frame_desc_strm.GetData());
}
if (exe_ctx.HasThreadScope())
@@ -726,13 +860,13 @@ SBThread::StepOutOfFrame (lldb::SBFrame &sb_frame)
Thread *thread = exe_ctx.GetThreadPtr();
ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut (abort_other_plans,
- NULL,
- false,
- stop_other_threads,
- eVoteYes,
+ NULL,
+ false,
+ stop_other_threads,
+ eVoteYes,
eVoteNoOpinion,
frame_sp->GetFrameIndex()));
-
+
// This returns an error, we should use it!
ResumeNewPlan (exe_ctx, new_plan_sp.get());
}
@@ -749,13 +883,14 @@ SBThread::StepInstruction (bool step_over)
if (log)
- log->Printf ("SBThread(%p)::StepInstruction (step_over=%i)", exe_ctx.GetThreadPtr(), step_over);
-
+ log->Printf ("SBThread(%p)::StepInstruction (step_over=%i)",
+ static_cast<void*>(exe_ctx.GetThreadPtr()), step_over);
+
if (exe_ctx.HasThreadScope())
{
Thread *thread = exe_ctx.GetThreadPtr();
ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepSingleInstruction (step_over, true, true));
-
+
// This returns an error, we should use it!
ResumeNewPlan (exe_ctx, new_plan_sp.get());
}
@@ -771,8 +906,9 @@ SBThread::RunToAddress (lldb::addr_t addr)
if (log)
- log->Printf ("SBThread(%p)::RunToAddress (addr=0x%" PRIx64 ")", exe_ctx.GetThreadPtr(), addr);
-
+ log->Printf ("SBThread(%p)::RunToAddress (addr=0x%" PRIx64 ")",
+ static_cast<void*>(exe_ctx.GetThreadPtr()), addr);
+
if (exe_ctx.HasThreadScope())
{
bool abort_other_plans = false;
@@ -783,7 +919,7 @@ SBThread::RunToAddress (lldb::addr_t addr)
Thread *thread = exe_ctx.GetThreadPtr();
ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads));
-
+
// This returns an error, we should use it!
ResumeNewPlan (exe_ctx, new_plan_sp.get());
}
@@ -797,7 +933,7 @@ SBThread::StepOverUntil (lldb::SBFrame &sb_frame,
SBError sb_error;
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
char path[PATH_MAX];
-
+
Mutex::Locker api_locker;
ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
@@ -808,11 +944,10 @@ SBThread::StepOverUntil (lldb::SBFrame &sb_frame,
SBStream frame_desc_strm;
sb_frame.GetDescription (frame_desc_strm);
sb_file_spec->GetPath (path, sizeof(path));
- log->Printf ("SBThread(%p)::StepOverUntil (frame = SBFrame(%p): %s, file+line = %s:%u)",
- exe_ctx.GetThreadPtr(),
- frame_sp.get(),
- frame_desc_strm.GetData(),
- path, line);
+ log->Printf ("SBThread(%p)::StepOverUntil (frame = SBFrame(%p): %s, file+line = %s:%u)",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ static_cast<void*>(frame_sp.get()),
+ frame_desc_strm.GetData(), path, line);
}
if (exe_ctx.HasThreadScope())
@@ -825,14 +960,14 @@ SBThread::StepOverUntil (lldb::SBFrame &sb_frame,
sb_error.SetErrorString("invalid line argument");
return sb_error;
}
-
+
if (!frame_sp)
{
frame_sp = thread->GetSelectedFrame ();
if (!frame_sp)
frame_sp = thread->GetStackFrameAtIndex (0);
}
-
+
SymbolContext frame_sc;
if (!frame_sp)
{
@@ -845,13 +980,13 @@ SBThread::StepOverUntil (lldb::SBFrame &sb_frame,
eSymbolContextFunction |
eSymbolContextLineEntry |
eSymbolContextSymbol );
-
+
if (frame_sc.comp_unit == NULL)
{
sb_error.SetErrorStringWithFormat("frame %u doesn't have debug information", frame_sp->GetFrameIndex());
return sb_error;
}
-
+
FileSpec step_file_spec;
if (sb_file_spec.IsValid())
{
@@ -868,15 +1003,15 @@ SBThread::StepOverUntil (lldb::SBFrame &sb_frame,
return sb_error;
}
}
-
+
// Grab the current function, then we will make sure the "until" address is
// within the function. We discard addresses that are out of the current
// function, and then if there are no addresses remaining, give an appropriate
// error message.
-
+
bool all_in_function = true;
AddressRange fun_range = frame_sc.function->GetAddressRange();
-
+
std::vector<addr_t> step_over_until_addrs;
const bool abort_other_plans = false;
const bool stop_other_threads = false;
@@ -908,7 +1043,7 @@ SBThread::StepOverUntil (lldb::SBFrame &sb_frame,
}
}
}
-
+
if (step_over_until_addrs.empty())
{
if (all_in_function)
@@ -947,7 +1082,9 @@ SBThread::JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line)
ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
if (log)
- log->Printf ("SBThread(%p)::JumpToLine (file+line = %s:%u)", exe_ctx.GetThreadPtr(), file_spec->GetPath().c_str(), line);
+ log->Printf ("SBThread(%p)::JumpToLine (file+line = %s:%u)",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ file_spec->GetPath().c_str(), line);
if (!exe_ctx.HasThreadScope())
{
@@ -966,7 +1103,7 @@ SBError
SBThread::ReturnFromFrame (SBFrame &frame, SBValue &return_value)
{
SBError sb_error;
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
Mutex::Locker api_locker;
@@ -974,14 +1111,16 @@ SBThread::ReturnFromFrame (SBFrame &frame, SBValue &return_value)
if (log)
- log->Printf ("SBThread(%p)::ReturnFromFrame (frame=%d)", exe_ctx.GetThreadPtr(), frame.GetFrameID());
-
+ log->Printf ("SBThread(%p)::ReturnFromFrame (frame=%d)",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ frame.GetFrameID());
+
if (exe_ctx.HasThreadScope())
{
Thread *thread = exe_ctx.GetThreadPtr();
sb_error.SetError (thread->ReturnFromFrame(frame.GetFrameSP(), return_value.GetSP()));
}
-
+
return sb_error;
}
@@ -1003,11 +1142,13 @@ SBThread::Suspend()
else
{
if (log)
- log->Printf ("SBThread(%p)::Suspend() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::Suspend() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
if (log)
- log->Printf ("SBThread(%p)::Suspend() => %i", exe_ctx.GetThreadPtr(), result);
+ log->Printf ("SBThread(%p)::Suspend() => %i",
+ static_cast<void*>(exe_ctx.GetThreadPtr()), result);
return result;
}
@@ -1022,17 +1163,20 @@ SBThread::Resume ()
Process::StopLocker stop_locker;
if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
{
- exe_ctx.GetThreadPtr()->SetResumeState (eStateRunning);
+ const bool override_suspend = true;
+ exe_ctx.GetThreadPtr()->SetResumeState (eStateRunning, override_suspend);
result = true;
}
else
{
if (log)
- log->Printf ("SBThread(%p)::Resume() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::Resume() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
if (log)
- log->Printf ("SBThread(%p)::Resume() => %i", exe_ctx.GetThreadPtr(), result);
+ log->Printf ("SBThread(%p)::Resume() => %i",
+ static_cast<void*>(exe_ctx.GetThreadPtr()), result);
return result;
}
@@ -1070,8 +1214,10 @@ SBThread::GetProcess ()
{
SBStream frame_desc_strm;
sb_process.GetDescription (frame_desc_strm);
- log->Printf ("SBThread(%p)::GetProcess () => SBProcess(%p): %s", exe_ctx.GetThreadPtr(),
- sb_process.GetSP().get(), frame_desc_strm.GetData());
+ log->Printf ("SBThread(%p)::GetProcess () => SBProcess(%p): %s",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ static_cast<void*>(sb_process.GetSP().get()),
+ frame_desc_strm.GetData());
}
return sb_process;
@@ -1096,12 +1242,14 @@ SBThread::GetNumFrames ()
else
{
if (log)
- log->Printf ("SBThread(%p)::GetNumFrames() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::GetNumFrames() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
if (log)
- log->Printf ("SBThread(%p)::GetNumFrames () => %u", exe_ctx.GetThreadPtr(), num_frames);
+ log->Printf ("SBThread(%p)::GetNumFrames () => %u",
+ static_cast<void*>(exe_ctx.GetThreadPtr()), num_frames);
return num_frames;
}
@@ -1127,7 +1275,8 @@ SBThread::GetFrameAtIndex (uint32_t idx)
else
{
if (log)
- log->Printf ("SBThread(%p)::GetFrameAtIndex() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::GetFrameAtIndex() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
@@ -1135,8 +1284,10 @@ SBThread::GetFrameAtIndex (uint32_t idx)
{
SBStream frame_desc_strm;
sb_frame.GetDescription (frame_desc_strm);
- log->Printf ("SBThread(%p)::GetFrameAtIndex (idx=%d) => SBFrame(%p): %s",
- exe_ctx.GetThreadPtr(), idx, frame_sp.get(), frame_desc_strm.GetData());
+ log->Printf ("SBThread(%p)::GetFrameAtIndex (idx=%d) => SBFrame(%p): %s",
+ static_cast<void*>(exe_ctx.GetThreadPtr()), idx,
+ static_cast<void*>(frame_sp.get()),
+ frame_desc_strm.GetData());
}
return sb_frame;
@@ -1163,7 +1314,8 @@ SBThread::GetSelectedFrame ()
else
{
if (log)
- log->Printf ("SBThread(%p)::GetSelectedFrame() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::GetSelectedFrame() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
@@ -1171,8 +1323,10 @@ SBThread::GetSelectedFrame ()
{
SBStream frame_desc_strm;
sb_frame.GetDescription (frame_desc_strm);
- log->Printf ("SBThread(%p)::GetSelectedFrame () => SBFrame(%p): %s",
- exe_ctx.GetThreadPtr(), frame_sp.get(), frame_desc_strm.GetData());
+ log->Printf ("SBThread(%p)::GetSelectedFrame () => SBFrame(%p): %s",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ static_cast<void*>(frame_sp.get()),
+ frame_desc_strm.GetData());
}
return sb_frame;
@@ -1204,7 +1358,8 @@ SBThread::SetSelectedFrame (uint32_t idx)
else
{
if (log)
- log->Printf ("SBThread(%p)::SetSelectedFrame() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::SetSelectedFrame() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
@@ -1212,8 +1367,10 @@ SBThread::SetSelectedFrame (uint32_t idx)
{
SBStream frame_desc_strm;
sb_frame.GetDescription (frame_desc_strm);
- log->Printf ("SBThread(%p)::SetSelectedFrame (idx=%u) => SBFrame(%p): %s",
- exe_ctx.GetThreadPtr(), idx, frame_sp.get(), frame_desc_strm.GetData());
+ log->Printf ("SBThread(%p)::SetSelectedFrame (idx=%u) => SBFrame(%p): %s",
+ static_cast<void*>(exe_ctx.GetThreadPtr()), idx,
+ static_cast<void*>(frame_sp.get()),
+ frame_desc_strm.GetData());
}
return sb_frame;
}
@@ -1316,7 +1473,11 @@ SBThread::GetExtendedBacktraceThread (const char *type)
const char *queue_name = new_thread_sp->GetQueueName();
if (queue_name == NULL)
queue_name = "";
- log->Printf ("SBThread(%p)::GetExtendedBacktraceThread() => new extended Thread created (%p) with queue_id 0x%" PRIx64 " queue name '%s'", exe_ctx.GetThreadPtr(), new_thread_sp.get(), new_thread_sp->GetQueueID(), queue_name);
+ log->Printf ("SBThread(%p)::GetExtendedBacktraceThread() => new extended Thread created (%p) with queue_id 0x%" PRIx64 " queue name '%s'",
+ static_cast<void*>(exe_ctx.GetThreadPtr()),
+ static_cast<void*>(new_thread_sp.get()),
+ new_thread_sp->GetQueueID(),
+ queue_name);
}
}
}
@@ -1326,10 +1487,14 @@ SBThread::GetExtendedBacktraceThread (const char *type)
else
{
if (log)
- log->Printf ("SBThread(%p)::GetExtendedBacktraceThread() => error: process is running", exe_ctx.GetThreadPtr());
+ log->Printf ("SBThread(%p)::GetExtendedBacktraceThread() => error: process is running",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}
+ if (log && sb_origin_thread.IsValid() == false)
+ log->Printf("SBThread(%p)::GetExtendedBacktraceThread() is not returning a Valid thread",
+ static_cast<void*>(exe_ctx.GetThreadPtr()));
return sb_origin_thread;
}
@@ -1341,3 +1506,12 @@ SBThread::GetExtendedBacktraceOriginatingIndexID ()
return thread_sp->GetExtendedBacktraceOriginatingIndexID();
return LLDB_INVALID_INDEX32;
}
+
+bool
+SBThread::SafeToCallFunctions ()
+{
+ ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
+ if (thread_sp)
+ return thread_sp->SafeToCallFunctions();
+ return true;
+}
diff --git a/source/API/SBType.cpp b/source/API/SBType.cpp
index 5ca7ddf3d813..064fb32c953f 100644
--- a/source/API/SBType.cpp
+++ b/source/API/SBType.cpp
@@ -9,6 +9,7 @@
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBType.h"
+#include "lldb/API/SBTypeEnumMember.h"
#include "lldb/API/SBStream.h"
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Log.h"
@@ -17,6 +18,8 @@
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Symbol/Type.h"
+#include "clang/AST/Decl.h"
+
using namespace lldb;
using namespace lldb_private;
using namespace clang;
@@ -364,6 +367,27 @@ SBType::GetVirtualBaseClassAtIndex (uint32_t idx)
return sb_type_member;
}
+SBTypeEnumMemberList
+SBType::GetEnumMembers ()
+{
+ SBTypeEnumMemberList sb_enum_member_list;
+ if (IsValid())
+ {
+ const clang::EnumDecl *enum_decl = m_opaque_sp->GetClangASTType(true).GetFullyUnqualifiedType().GetAsEnumDecl();
+ if (enum_decl)
+ {
+ clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
+ for (enum_pos = enum_decl->enumerator_begin(), enum_end_pos = enum_decl->enumerator_end(); enum_pos != enum_end_pos; ++enum_pos)
+ {
+ SBTypeEnumMember enum_member;
+ enum_member.reset(new TypeEnumMemberImpl(*enum_pos, ClangASTType(m_opaque_sp->GetClangASTContext(true), enum_decl->getIntegerType())));
+ sb_enum_member_list.Append(enum_member);
+ }
+ }
+ }
+ return sb_enum_member_list;
+}
+
SBTypeMember
SBType::GetFieldAtIndex (uint32_t idx)
{
@@ -414,6 +438,14 @@ SBType::GetName()
return m_opaque_sp->GetName().GetCString();
}
+const char *
+SBType::GetDisplayTypeName ()
+{
+ if (!IsValid())
+ return "";
+ return m_opaque_sp->GetDisplayTypeName().GetCString();
+}
+
lldb::TypeClass
SBType::GetTypeClass ()
{
diff --git a/source/API/SBTypeEnumMember.cpp b/source/API/SBTypeEnumMember.cpp
new file mode 100644
index 000000000000..47c57dd213fb
--- /dev/null
+++ b/source/API/SBTypeEnumMember.cpp
@@ -0,0 +1,192 @@
+//===-- SBTypeEnumMember.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/SBDefines.h"
+#include "lldb/API/SBType.h"
+#include "lldb/API/SBTypeEnumMember.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/Type.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace clang;
+
+SBTypeEnumMember::SBTypeEnumMember() :
+ m_opaque_sp()
+{
+}
+
+SBTypeEnumMember::~SBTypeEnumMember()
+{
+}
+SBTypeEnumMember::SBTypeEnumMember (const lldb::TypeEnumMemberImplSP &enum_member_sp) :
+ m_opaque_sp(enum_member_sp)
+{
+}
+
+SBTypeEnumMember::SBTypeEnumMember (const SBTypeEnumMember& rhs) :
+ m_opaque_sp()
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ m_opaque_sp.reset(new TypeEnumMemberImpl(rhs.ref()));
+ }
+}
+
+SBTypeEnumMember&
+SBTypeEnumMember::operator = (const SBTypeEnumMember& rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ m_opaque_sp.reset(new TypeEnumMemberImpl(rhs.ref()));
+ }
+ return *this;
+}
+
+bool
+SBTypeEnumMember::IsValid() const
+{
+ return m_opaque_sp.get();
+}
+
+const char *
+SBTypeEnumMember::GetName ()
+{
+ if (m_opaque_sp.get())
+ return m_opaque_sp->GetName().GetCString();
+ return NULL;
+}
+
+int64_t
+SBTypeEnumMember::GetValueAsSigned()
+{
+ if (m_opaque_sp.get())
+ return m_opaque_sp->GetValueAsSigned();
+ return 0;
+}
+
+uint64_t
+SBTypeEnumMember::GetValueAsUnsigned()
+{
+ if (m_opaque_sp.get())
+ return m_opaque_sp->GetValueAsUnsigned();
+ return 0;
+}
+
+SBType
+SBTypeEnumMember::GetType ()
+{
+ SBType sb_type;
+ if (m_opaque_sp.get())
+ {
+ sb_type.SetSP(m_opaque_sp->GetIntegerType());
+ }
+ return sb_type;
+
+}
+
+void
+SBTypeEnumMember::reset(TypeEnumMemberImpl *type_member_impl)
+{
+ m_opaque_sp.reset(type_member_impl);
+}
+
+TypeEnumMemberImpl &
+SBTypeEnumMember::ref ()
+{
+ if (m_opaque_sp.get() == NULL)
+ m_opaque_sp.reset (new TypeEnumMemberImpl());
+ return *m_opaque_sp.get();
+}
+
+const TypeEnumMemberImpl &
+SBTypeEnumMember::ref () const
+{
+ return *m_opaque_sp.get();
+}
+
+
+SBTypeEnumMemberList::SBTypeEnumMemberList() :
+ m_opaque_ap(new TypeEnumMemberListImpl())
+{
+}
+
+SBTypeEnumMemberList::SBTypeEnumMemberList(const SBTypeEnumMemberList& rhs) :
+ m_opaque_ap(new TypeEnumMemberListImpl())
+{
+ for (uint32_t i = 0, rhs_size = const_cast<SBTypeEnumMemberList&>(rhs).GetSize(); i < rhs_size; i++)
+ Append(const_cast<SBTypeEnumMemberList&>(rhs).GetTypeEnumMemberAtIndex(i));
+}
+
+bool
+SBTypeEnumMemberList::IsValid ()
+{
+ return (m_opaque_ap.get() != NULL);
+}
+
+SBTypeEnumMemberList&
+SBTypeEnumMemberList::operator = (const SBTypeEnumMemberList& rhs)
+{
+ if (this != &rhs)
+ {
+ m_opaque_ap.reset (new TypeEnumMemberListImpl());
+ for (uint32_t i = 0, rhs_size = const_cast<SBTypeEnumMemberList&>(rhs).GetSize(); i < rhs_size; i++)
+ Append(const_cast<SBTypeEnumMemberList&>(rhs).GetTypeEnumMemberAtIndex(i));
+ }
+ return *this;
+}
+
+void
+SBTypeEnumMemberList::Append (SBTypeEnumMember enum_member)
+{
+ if (enum_member.IsValid())
+ m_opaque_ap->Append (enum_member.m_opaque_sp);
+}
+
+SBTypeEnumMember
+SBTypeEnumMemberList::GetTypeEnumMemberAtIndex(uint32_t index)
+{
+ if (m_opaque_ap.get())
+ return SBTypeEnumMember(m_opaque_ap->GetTypeEnumMemberAtIndex(index));
+ return SBTypeEnumMember();
+}
+
+uint32_t
+SBTypeEnumMemberList::GetSize()
+{
+ return m_opaque_ap->GetSize();
+}
+
+SBTypeEnumMemberList::~SBTypeEnumMemberList()
+{
+}
+
+bool
+SBTypeEnumMember::GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_sp.get())
+ {
+ if( m_opaque_sp->GetIntegerType()->GetDescription(strm, description_level) )
+ {
+ strm.Printf(" %s", m_opaque_sp->GetName().GetCString());
+ }
+ }
+ else
+ {
+ strm.PutCString ("No value");
+ }
+ return true;
+}
diff --git a/source/API/SBUnixSignals.cpp b/source/API/SBUnixSignals.cpp
new file mode 100644
index 000000000000..ca321d82fd60
--- /dev/null
+++ b/source/API/SBUnixSignals.cpp
@@ -0,0 +1,199 @@
+//===-- SBUnixSignals.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-defines.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Core/Log.h"
+
+#include "lldb/API/SBUnixSignals.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBUnixSignals::SBUnixSignals ()
+{}
+
+SBUnixSignals::SBUnixSignals (const SBUnixSignals &rhs) :
+ m_opaque_wp(rhs.m_opaque_wp)
+{
+}
+
+SBUnixSignals::SBUnixSignals (ProcessSP &process_sp) :
+ m_opaque_wp(process_sp)
+{
+}
+
+const SBUnixSignals&
+SBUnixSignals::operator = (const SBUnixSignals& rhs)
+{
+ if (this != &rhs)
+ m_opaque_wp = rhs.m_opaque_wp;
+ return *this;
+}
+
+SBUnixSignals::~SBUnixSignals()
+{
+}
+
+ProcessSP
+SBUnixSignals::GetSP() const
+{
+ return m_opaque_wp.lock();
+}
+
+void
+SBUnixSignals::SetSP (const ProcessSP &process_sp)
+{
+ m_opaque_wp = process_sp;
+}
+
+void
+SBUnixSignals::Clear ()
+{
+ m_opaque_wp.reset();
+}
+
+bool
+SBUnixSignals::IsValid() const
+{
+ return (bool) GetSP();
+}
+
+const char *
+SBUnixSignals::GetSignalAsCString (int32_t signo) const
+{
+ ProcessSP process_sp(GetSP());
+ if (process_sp) return process_sp->GetUnixSignals().GetSignalAsCString(signo);
+ return NULL;
+}
+
+int32_t
+SBUnixSignals::GetSignalNumberFromName (const char *name) const
+{
+ ProcessSP process_sp(GetSP());
+ if (process_sp) return process_sp->GetUnixSignals().GetSignalNumberFromName(name);
+ return -1;
+}
+
+bool
+SBUnixSignals::GetShouldSuppress (int32_t signo) const
+{
+ ProcessSP process_sp(GetSP());
+ if (process_sp) return process_sp->GetUnixSignals().GetShouldSuppress(signo);
+ return false;
+}
+
+bool
+SBUnixSignals::SetShouldSuppress (int32_t signo, bool value)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ ProcessSP process_sp(GetSP());
+
+ if (log)
+ {
+ log->Printf ("SBUnixSignals(%p)::SetShouldSuppress (signo=%d, value=%d)",
+ static_cast<void*>(process_sp.get()),
+ signo,
+ value);
+ }
+
+ if (process_sp) return process_sp->GetUnixSignals().SetShouldSuppress(signo, value);
+ return false;
+}
+
+bool
+SBUnixSignals::GetShouldStop (int32_t signo) const
+{
+ ProcessSP process_sp(GetSP());
+ if (process_sp) return process_sp->GetUnixSignals().GetShouldStop(signo);
+ return false;
+}
+
+bool
+SBUnixSignals::SetShouldStop (int32_t signo, bool value)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ ProcessSP process_sp(GetSP());
+
+ if (log)
+ {
+ log->Printf ("SBUnixSignals(%p)::SetShouldStop (signo=%d, value=%d)",
+ static_cast<void*>(process_sp.get()),
+ signo,
+ value);
+ }
+
+ if (process_sp) return process_sp->GetUnixSignals().SetShouldStop(signo, value);
+ return false;
+}
+
+bool
+SBUnixSignals::GetShouldNotify (int32_t signo) const
+{
+ ProcessSP process_sp(GetSP());
+ if (process_sp) return process_sp->GetUnixSignals().GetShouldNotify(signo);
+ return false;
+}
+
+bool
+SBUnixSignals::SetShouldNotify (int32_t signo, bool value)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ ProcessSP process_sp(GetSP());
+
+ if (log)
+ {
+ log->Printf ("SBUnixSignals(%p)::SetShouldNotify (signo=%d, value=%d)",
+ static_cast<void*>(process_sp.get()),
+ signo,
+ value);
+ }
+
+ if (process_sp) return process_sp->GetUnixSignals().SetShouldNotify(signo, value);
+ return false;
+}
+
+int32_t
+SBUnixSignals::GetNumSignals () const
+{
+ if (auto process_sp = GetSP())
+ {
+ // only valid while we hold process_sp
+ UnixSignals *unix_signals_ptr = &process_sp->GetUnixSignals();
+ int32_t num_signals = 0;
+ for (int32_t signo = unix_signals_ptr->GetFirstSignalNumber();
+ signo != LLDB_INVALID_SIGNAL_NUMBER;
+ signo = unix_signals_ptr->GetNextSignalNumber(signo))
+ {
+ num_signals++;
+ }
+ return num_signals;
+ }
+ return LLDB_INVALID_SIGNAL_NUMBER;
+}
+
+int32_t
+SBUnixSignals::GetSignalAtIndex (int32_t index) const
+{
+ if (auto process_sp = GetSP())
+ {
+ // only valid while we hold process_sp
+ UnixSignals *unix_signals_ptr = &process_sp->GetUnixSignals();
+ int32_t idx = 0;
+ for (int32_t signo = unix_signals_ptr->GetFirstSignalNumber();
+ signo != LLDB_INVALID_SIGNAL_NUMBER;
+ signo = unix_signals_ptr->GetNextSignalNumber(signo))
+ {
+ if (index == idx) return signo;
+ idx++;
+ }
+ }
+ return LLDB_INVALID_SIGNAL_NUMBER;
+}
diff --git a/source/API/SBValue.cpp b/source/API/SBValue.cpp
index 4bd018352ff2..3a9621b1e3bc 100644
--- a/source/API/SBValue.cpp
+++ b/source/API/SBValue.cpp
@@ -58,7 +58,7 @@ public:
ValueImpl ()
{
}
-
+
ValueImpl (lldb::ValueObjectSP in_valobj_sp,
lldb::DynamicValueType use_dynamic,
bool use_synthetic,
@@ -71,7 +71,7 @@ public:
if (!m_name.IsEmpty() && m_valobj_sp)
m_valobj_sp->SetName(m_name);
}
-
+
ValueImpl (const ValueImpl& rhs) :
m_valobj_sp(rhs.m_valobj_sp),
m_use_dynamic(rhs.m_use_dynamic),
@@ -79,7 +79,7 @@ public:
m_name (rhs.m_name)
{
}
-
+
ValueImpl &
operator = (const ValueImpl &rhs)
{
@@ -92,7 +92,7 @@ public:
}
return *this;
}
-
+
bool
IsValid ()
{
@@ -115,13 +115,13 @@ public:
return false;
}
}
-
+
lldb::ValueObjectSP
GetRootSP ()
{
return m_valobj_sp;
}
-
+
lldb::ValueObjectSP
GetSP (Process::StopLocker &stop_locker, Mutex::Locker &api_locker, Error &error)
{
@@ -131,26 +131,27 @@ public:
error.SetErrorString("invalid value object");
return m_valobj_sp;
}
-
+
lldb::ValueObjectSP value_sp = m_valobj_sp;
-
+
Target *target = value_sp->GetTargetSP().get();
if (target)
api_locker.Lock(target->GetAPIMutex());
else
return ValueObjectSP();
-
+
ProcessSP process_sp(value_sp->GetProcessSP());
if (process_sp && !stop_locker.TryLock (&process_sp->GetRunLock()))
{
// We don't allow people to play around with ValueObject if the process is running.
// If you want to look at values, pause the process, then look.
if (log)
- log->Printf ("SBValue(%p)::GetSP() => error: process is running", value_sp.get());
+ log->Printf ("SBValue(%p)::GetSP() => error: process is running",
+ static_cast<void*>(value_sp.get()));
error.SetErrorString ("process must be stopped.");
return ValueObjectSP();
}
-
+
if (value_sp->GetDynamicValue(m_use_dynamic))
value_sp = value_sp->GetDynamicValue(m_use_dynamic);
if (value_sp->GetSyntheticValue(m_use_synthetic))
@@ -159,34 +160,34 @@ public:
error.SetErrorString("invalid value object");
if (!m_name.IsEmpty())
value_sp->SetName(m_name);
-
+
return value_sp;
}
-
+
void
SetUseDynamic (lldb::DynamicValueType use_dynamic)
{
m_use_dynamic = use_dynamic;
}
-
+
void
SetUseSynthetic (bool use_synthetic)
{
m_use_synthetic = use_synthetic;
}
-
+
lldb::DynamicValueType
GetUseDynamic ()
{
return m_use_dynamic;
}
-
+
bool
GetUseSynthetic ()
{
return m_use_synthetic;
}
-
+
// All the derived values that we would make from the m_valobj_sp will share
// the ExecutionContext with m_valobj_sp, so we don't need to do the calculations
// in GetSP to return the Target, Process, Thread or Frame. It is convenient to
@@ -199,7 +200,7 @@ public:
else
return TargetSP();
}
-
+
ProcessSP
GetProcessSP ()
{
@@ -208,7 +209,7 @@ public:
else
return ProcessSP();
}
-
+
ThreadSP
GetThreadSP ()
{
@@ -217,7 +218,7 @@ public:
else
return ThreadSP();
}
-
+
StackFrameSP
GetFrameSP ()
{
@@ -226,7 +227,7 @@ public:
else
return StackFrameSP();
}
-
+
private:
lldb::ValueObjectSP m_valobj_sp;
lldb::DynamicValueType m_use_dynamic;
@@ -337,16 +338,18 @@ SBValue::GetName()
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
name = value_sp->GetName().GetCString();
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
{
if (name)
- log->Printf ("SBValue(%p)::GetName () => \"%s\"", value_sp.get(), name);
+ log->Printf ("SBValue(%p)::GetName () => \"%s\"",
+ static_cast<void*>(value_sp.get()), name);
else
- log->Printf ("SBValue(%p)::GetName () => NULL", value_sp.get());
+ log->Printf ("SBValue(%p)::GetName () => NULL",
+ static_cast<void*>(value_sp.get()));
}
-
+
return name;
}
@@ -361,13 +364,40 @@ SBValue::GetTypeName ()
{
name = value_sp->GetQualifiedTypeName().GetCString();
}
+
+ if (log)
+ {
+ if (name)
+ log->Printf ("SBValue(%p)::GetTypeName () => \"%s\"",
+ static_cast<void*>(value_sp.get()), name);
+ else
+ log->Printf ("SBValue(%p)::GetTypeName () => NULL",
+ static_cast<void*>(value_sp.get()));
+ }
+
+ return name;
+}
+
+const char *
+SBValue::GetDisplayTypeName ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ const char *name = NULL;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ name = value_sp->GetDisplayTypeName().GetCString();
+ }
if (log)
{
if (name)
- log->Printf ("SBValue(%p)::GetTypeName () => \"%s\"", value_sp.get(), name);
+ log->Printf ("SBValue(%p)::GetTypeName () => \"%s\"",
+ static_cast<void*>(value_sp.get()), name);
else
- log->Printf ("SBValue(%p)::GetTypeName () => NULL", value_sp.get());
+ log->Printf ("SBValue(%p)::GetTypeName () => NULL",
+ static_cast<void*>(value_sp.get()));
}
return name;
@@ -378,17 +408,19 @@ SBValue::GetByteSize ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
size_t result = 0;
-
+
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
{
result = value_sp->GetByteSize();
}
-
+
if (log)
- log->Printf ("SBValue(%p)::GetByteSize () => %" PRIu64, value_sp.get(), (uint64_t)result);
-
+ log->Printf ("SBValue(%p)::GetByteSize () => %" PRIu64,
+ static_cast<void*>(value_sp.get()),
+ static_cast<uint64_t>(result));
+
return result;
}
@@ -396,18 +428,19 @@ bool
SBValue::IsInScope ()
{
bool result = false;
-
+
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
{
result = value_sp->IsInScope ();
}
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBValue(%p)::IsInScope () => %i", value_sp.get(), result);
-
+ log->Printf ("SBValue(%p)::IsInScope () => %i",
+ static_cast<void*>(value_sp.get()), result);
+
return result;
}
@@ -415,7 +448,7 @@ const char *
SBValue::GetValue ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
const char *cstr = NULL;
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
@@ -426,11 +459,13 @@ SBValue::GetValue ()
if (log)
{
if (cstr)
- log->Printf ("SBValue(%p)::GetValue() => \"%s\"", value_sp.get(), cstr);
+ log->Printf ("SBValue(%p)::GetValue() => \"%s\"",
+ static_cast<void*>(value_sp.get()), cstr);
else
- log->Printf ("SBValue(%p)::GetValue() => NULL", value_sp.get());
+ log->Printf ("SBValue(%p)::GetValue() => NULL",
+ static_cast<void*>(value_sp.get()));
}
-
+
return cstr;
}
@@ -442,20 +477,44 @@ SBValue::GetValueType ()
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
result = value_sp->GetValueType();
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
{
switch (result)
{
- case eValueTypeInvalid: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeInvalid", value_sp.get()); break;
- case eValueTypeVariableGlobal: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableGlobal", value_sp.get()); break;
- case eValueTypeVariableStatic: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableStatic", value_sp.get()); break;
- case eValueTypeVariableArgument:log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableArgument", value_sp.get()); break;
- case eValueTypeVariableLocal: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableLocal", value_sp.get()); break;
- case eValueTypeRegister: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegister", value_sp.get()); break;
- case eValueTypeRegisterSet: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegisterSet", value_sp.get()); break;
- case eValueTypeConstResult: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeConstResult", value_sp.get()); break;
+ case eValueTypeInvalid:
+ log->Printf ("SBValue(%p)::GetValueType () => eValueTypeInvalid",
+ static_cast<void*>(value_sp.get()));
+ break;
+ case eValueTypeVariableGlobal:
+ log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableGlobal",
+ static_cast<void*>(value_sp.get()));
+ break;
+ case eValueTypeVariableStatic:
+ log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableStatic",
+ static_cast<void*>(value_sp.get()));
+ break;
+ case eValueTypeVariableArgument:
+ log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableArgument",
+ static_cast<void*>(value_sp.get()));
+ break;
+ case eValueTypeVariableLocal:
+ log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableLocal",
+ static_cast<void*>(value_sp.get()));
+ break;
+ case eValueTypeRegister:
+ log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegister",
+ static_cast<void*>(value_sp.get()));
+ break;
+ case eValueTypeRegisterSet:
+ log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegisterSet",
+ static_cast<void*>(value_sp.get()));
+ break;
+ case eValueTypeConstResult:
+ log->Printf ("SBValue(%p)::GetValueType () => eValueTypeConstResult",
+ static_cast<void*>(value_sp.get()));
+ break;
}
}
return result;
@@ -475,9 +534,11 @@ SBValue::GetObjectDescription ()
if (log)
{
if (cstr)
- log->Printf ("SBValue(%p)::GetObjectDescription() => \"%s\"", value_sp.get(), cstr);
+ log->Printf ("SBValue(%p)::GetObjectDescription() => \"%s\"",
+ static_cast<void*>(value_sp.get()), cstr);
else
- log->Printf ("SBValue(%p)::GetObjectDescription() => NULL", value_sp.get());
+ log->Printf ("SBValue(%p)::GetObjectDescription() => NULL",
+ static_cast<void*>(value_sp.get()));
}
return cstr;
}
@@ -498,9 +559,12 @@ SBValue::GetType()
if (log)
{
if (type_sp)
- log->Printf ("SBValue(%p)::GetType => SBType(%p)", value_sp.get(), type_sp.get());
+ log->Printf ("SBValue(%p)::GetType => SBType(%p)",
+ static_cast<void*>(value_sp.get()),
+ static_cast<void*>(type_sp.get()));
else
- log->Printf ("SBValue(%p)::GetType => NULL", value_sp.get());
+ log->Printf ("SBValue(%p)::GetType => NULL",
+ static_cast<void*>(value_sp.get()));
}
return sb_type;
}
@@ -517,8 +581,9 @@ SBValue::GetValueDidChange ()
result = value_sp->GetValueDidChange ();
}
if (log)
- log->Printf ("SBValue(%p)::GetValueDidChange() => %i", value_sp.get(), result);
-
+ log->Printf ("SBValue(%p)::GetValueDidChange() => %i",
+ static_cast<void*>(value_sp.get()), result);
+
return result;
}
@@ -537,9 +602,11 @@ SBValue::GetSummary ()
if (log)
{
if (cstr)
- log->Printf ("SBValue(%p)::GetSummary() => \"%s\"", value_sp.get(), cstr);
+ log->Printf ("SBValue(%p)::GetSummary() => \"%s\"",
+ static_cast<void*>(value_sp.get()), cstr);
else
- log->Printf ("SBValue(%p)::GetSummary() => NULL", value_sp.get());
+ log->Printf ("SBValue(%p)::GetSummary() => NULL",
+ static_cast<void*>(value_sp.get()));
}
return cstr;
}
@@ -559,9 +626,11 @@ SBValue::GetLocation ()
if (log)
{
if (cstr)
- log->Printf ("SBValue(%p)::GetLocation() => \"%s\"", value_sp.get(), cstr);
+ log->Printf ("SBValue(%p)::GetLocation() => \"%s\"",
+ static_cast<void*>(value_sp.get()), cstr);
else
- log->Printf ("SBValue(%p)::GetLocation() => NULL", value_sp.get());
+ log->Printf ("SBValue(%p)::GetLocation() => NULL",
+ static_cast<void*>(value_sp.get()));
}
return cstr;
}
@@ -587,10 +656,11 @@ SBValue::SetValueFromCString (const char *value_str, lldb::SBError& error)
}
else
error.SetErrorStringWithFormat ("Could not get value: %s", locker.GetError().AsCString());
-
+
if (log)
- log->Printf ("SBValue(%p)::SetValueFromCString(\"%s\") => %i", value_sp.get(), value_str, success);
-
+ log->Printf ("SBValue(%p)::SetValueFromCString(\"%s\") => %i",
+ static_cast<void*>(value_sp.get()), value_str, success);
+
return success;
}
@@ -698,11 +768,11 @@ SBValue::CreateChildAtOffset (const char *name, uint32_t offset, SBType type)
{
if (new_value_sp)
log->Printf ("SBValue(%p)::CreateChildAtOffset => \"%s\"",
- value_sp.get(),
+ static_cast<void*>(value_sp.get()),
new_value_sp->GetName().AsCString());
else
log->Printf ("SBValue(%p)::CreateChildAtOffset => NULL",
- value_sp.get());
+ static_cast<void*>(value_sp.get()));
}
return sb_value;
}
@@ -757,15 +827,11 @@ SBValue::CreateValueFromExpression (const char *name, const char *expression, SB
{
if (new_value_sp)
log->Printf ("SBValue(%p)::CreateValueFromExpression(name=\"%s\", expression=\"%s\") => SBValue (%p)",
- value_sp.get(),
- name,
- expression,
- new_value_sp.get());
+ static_cast<void*>(value_sp.get()), name, expression,
+ static_cast<void*>(new_value_sp.get()));
else
log->Printf ("SBValue(%p)::CreateValueFromExpression(name=\"%s\", expression=\"%s\") => NULL",
- value_sp.get(),
- name,
- expression);
+ static_cast<void*>(value_sp.get()), name, expression);
}
return sb_value;
}
@@ -784,7 +850,7 @@ SBValue::CreateValueFromAddress(const char* name, lldb::addr_t address, SBType s
if (pointer_ast_type)
{
lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&address,sizeof(lldb::addr_t)));
-
+
ExecutionContext exe_ctx (value_sp->GetExecutionContextRef());
ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
pointer_ast_type,
@@ -792,7 +858,7 @@ SBValue::CreateValueFromAddress(const char* name, lldb::addr_t address, SBType s
buffer,
exe_ctx.GetByteOrder(),
exe_ctx.GetAddressByteSize()));
-
+
if (ptr_result_valobj_sp)
{
ptr_result_valobj_sp->GetValue().SetValueType(Value::eValueTypeLoadAddress);
@@ -808,9 +874,12 @@ SBValue::CreateValueFromAddress(const char* name, lldb::addr_t address, SBType s
if (log)
{
if (new_value_sp)
- log->Printf ("SBValue(%p)::CreateValueFromAddress => \"%s\"", value_sp.get(), new_value_sp->GetName().AsCString());
+ log->Printf ("SBValue(%p)::CreateValueFromAddress => \"%s\"",
+ static_cast<void*>(value_sp.get()),
+ new_value_sp->GetName().AsCString());
else
- log->Printf ("SBValue(%p)::CreateValueFromAddress => NULL", value_sp.get());
+ log->Printf ("SBValue(%p)::CreateValueFromAddress => NULL",
+ static_cast<void*>(value_sp.get()));
}
return sb_value;
}
@@ -825,7 +894,7 @@ SBValue::CreateValueFromData (const char* name, SBData data, SBType type)
if (value_sp)
{
ExecutionContext exe_ctx (value_sp->GetExecutionContextRef());
-
+
new_value_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
type.m_opaque_sp->GetClangASTType(false),
ConstString(name),
@@ -838,9 +907,12 @@ SBValue::CreateValueFromData (const char* name, SBData data, SBType type)
if (log)
{
if (new_value_sp)
- log->Printf ("SBValue(%p)::CreateValueFromData => \"%s\"", value_sp.get(), new_value_sp->GetName().AsCString());
+ log->Printf ("SBValue(%p)::CreateValueFromData => \"%s\"",
+ static_cast<void*>(value_sp.get()),
+ new_value_sp->GetName().AsCString());
else
- log->Printf ("SBValue(%p)::CreateValueFromData => NULL", value_sp.get());
+ log->Printf ("SBValue(%p)::CreateValueFromData => NULL",
+ static_cast<void*>(value_sp.get()));
}
return sb_value;
}
@@ -865,7 +937,7 @@ SBValue::GetChildAtIndex (uint32_t idx, lldb::DynamicValueType use_dynamic, bool
{
lldb::ValueObjectSP child_sp;
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
@@ -884,12 +956,14 @@ SBValue::GetChildAtIndex (uint32_t idx, lldb::DynamicValueType use_dynamic, bool
}
}
}
-
+
SBValue sb_value;
sb_value.SetSP (child_sp, use_dynamic, GetPreferSyntheticValue());
if (log)
- log->Printf ("SBValue(%p)::GetChildAtIndex (%u) => SBValue(%p)", value_sp.get(), idx, value_sp.get());
-
+ log->Printf ("SBValue(%p)::GetChildAtIndex (%u) => SBValue(%p)",
+ static_cast<void*>(value_sp.get()), idx,
+ static_cast<void*>(value_sp.get()));
+
return sb_value;
}
@@ -907,9 +981,11 @@ SBValue::GetIndexOfChildWithName (const char *name)
if (log)
{
if (idx == UINT32_MAX)
- log->Printf ("SBValue(%p)::GetIndexOfChildWithName (name=\"%s\") => NOT FOUND", value_sp.get(), name);
+ log->Printf ("SBValue(%p)::GetIndexOfChildWithName (name=\"%s\") => NOT FOUND",
+ static_cast<void*>(value_sp.get()), name);
else
- log->Printf ("SBValue(%p)::GetIndexOfChildWithName (name=\"%s\") => %u", value_sp.get(), name, idx);
+ log->Printf ("SBValue(%p)::GetIndexOfChildWithName (name=\"%s\") => %u",
+ static_cast<void*>(value_sp.get()), name, idx);
}
return idx;
}
@@ -921,7 +997,7 @@ SBValue::GetChildMemberWithName (const char *name)
TargetSP target_sp;
if (m_opaque_sp)
target_sp = m_opaque_sp->GetTargetSP();
-
+
if (target_sp)
use_dynamic_value = target_sp->GetPreferDynamicValue();
return GetChildMemberWithName (name, use_dynamic_value);
@@ -932,22 +1008,24 @@ SBValue::GetChildMemberWithName (const char *name, lldb::DynamicValueType use_dy
{
lldb::ValueObjectSP child_sp;
const ConstString str_name (name);
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
-
+
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
{
child_sp = value_sp->GetChildMemberWithName (str_name, true);
}
-
+
SBValue sb_value;
sb_value.SetSP(child_sp, use_dynamic_value, GetPreferSyntheticValue());
-
+
if (log)
- log->Printf ("SBValue(%p)::GetChildMemberWithName (name=\"%s\") => SBValue(%p)", value_sp.get(), name, value_sp.get());
-
+ log->Printf ("SBValue(%p)::GetChildMemberWithName (name=\"%s\") => SBValue(%p)",
+ static_cast<void*>(value_sp.get()), name,
+ static_cast<void*>(value_sp.get()));
+
return sb_value;
}
@@ -1049,13 +1127,15 @@ SBValue::GetValueForExpressionPath(const char* expr_path)
// using default values for all the fancy options, just do it if you can
child_sp = value_sp->GetValueForExpressionPath(expr_path);
}
-
+
SBValue sb_value;
sb_value.SetSP(child_sp,GetPreferDynamicValue(),GetPreferSyntheticValue());
-
+
if (log)
- log->Printf ("SBValue(%p)::GetValueForExpressionPath (expr_path=\"%s\") => SBValue(%p)", value_sp.get(), expr_path, value_sp.get());
-
+ log->Printf ("SBValue(%p)::GetValueForExpressionPath (expr_path=\"%s\") => SBValue(%p)",
+ static_cast<void*>(value_sp.get()), expr_path,
+ static_cast<void*>(value_sp.get()));
+
return sb_value;
}
@@ -1134,9 +1214,10 @@ SBValue::MightHaveChildren ()
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
has_children = value_sp->MightHaveChildren();
-
+
if (log)
- log->Printf ("SBValue(%p)::MightHaveChildren() => %i", value_sp.get(), has_children);
+ log->Printf ("SBValue(%p)::MightHaveChildren() => %i",
+ static_cast<void*>(value_sp.get()), has_children);
return has_children;
}
@@ -1144,16 +1225,17 @@ uint32_t
SBValue::GetNumChildren ()
{
uint32_t num_children = 0;
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
num_children = value_sp->GetNumChildren();
-
+
if (log)
- log->Printf ("SBValue(%p)::GetNumChildren () => %u", value_sp.get(), num_children);
-
+ log->Printf ("SBValue(%p)::GetNumChildren () => %u",
+ static_cast<void*>(value_sp.get()), num_children);
+
return num_children;
}
@@ -1171,8 +1253,10 @@ SBValue::Dereference ()
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBValue(%p)::Dereference () => SBValue(%p)", value_sp.get(), value_sp.get());
-
+ log->Printf ("SBValue(%p)::Dereference () => SBValue(%p)",
+ static_cast<void*>(value_sp.get()),
+ static_cast<void*>(value_sp.get()));
+
return sb_value;
}
@@ -1180,17 +1264,17 @@ bool
SBValue::TypeIsPointerType ()
{
bool is_ptr_type = false;
-
+
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp)
is_ptr_type = value_sp->IsPointerType();
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBValue(%p)::TypeIsPointerType () => %i", value_sp.get(), is_ptr_type);
-
-
+ log->Printf ("SBValue(%p)::TypeIsPointerType () => %i",
+ static_cast<void*>(value_sp.get()), is_ptr_type);
+
return is_ptr_type;
}
@@ -1218,9 +1302,12 @@ SBValue::GetTarget()
if (log)
{
if (target_sp.get() == NULL)
- log->Printf ("SBValue(%p)::GetTarget () => NULL", m_opaque_sp.get());
+ log->Printf ("SBValue(%p)::GetTarget () => NULL",
+ static_cast<void*>(m_opaque_sp.get()));
else
- log->Printf ("SBValue(%p)::GetTarget () => %p", m_opaque_sp.get(), target_sp.get());
+ log->Printf ("SBValue(%p)::GetTarget () => %p",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(target_sp.get()));
}
return sb_target;
}
@@ -1239,9 +1326,12 @@ SBValue::GetProcess()
if (log)
{
if (process_sp.get() == NULL)
- log->Printf ("SBValue(%p)::GetProcess () => NULL", m_opaque_sp.get());
+ log->Printf ("SBValue(%p)::GetProcess () => NULL",
+ static_cast<void*>(m_opaque_sp.get()));
else
- log->Printf ("SBValue(%p)::GetProcess () => %p", m_opaque_sp.get(), process_sp.get());
+ log->Printf ("SBValue(%p)::GetProcess () => %p",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(process_sp.get()));
}
return sb_process;
}
@@ -1260,9 +1350,12 @@ SBValue::GetThread()
if (log)
{
if (thread_sp.get() == NULL)
- log->Printf ("SBValue(%p)::GetThread () => NULL", m_opaque_sp.get());
+ log->Printf ("SBValue(%p)::GetThread () => NULL",
+ static_cast<void*>(m_opaque_sp.get()));
else
- log->Printf ("SBValue(%p)::GetThread () => %p", m_opaque_sp.get(), thread_sp.get());
+ log->Printf ("SBValue(%p)::GetThread () => %p",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(thread_sp.get()));
}
return sb_thread;
}
@@ -1281,9 +1374,12 @@ SBValue::GetFrame()
if (log)
{
if (frame_sp.get() == NULL)
- log->Printf ("SBValue(%p)::GetFrame () => NULL", m_opaque_sp.get());
+ log->Printf ("SBValue(%p)::GetFrame () => NULL",
+ static_cast<void*>(m_opaque_sp.get()));
else
- log->Printf ("SBValue(%p)::GetFrame () => %p", m_opaque_sp.get(), frame_sp.get());
+ log->Printf ("SBValue(%p)::GetFrame () => %p",
+ static_cast<void*>(m_opaque_sp.get()),
+ static_cast<void*>(frame_sp.get()));
}
return sb_frame;
}
@@ -1450,8 +1546,10 @@ SBValue::AddressOf()
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBValue(%p)::AddressOf () => SBValue(%p)", value_sp.get(), value_sp.get());
-
+ log->Printf ("SBValue(%p)::AddressOf () => SBValue(%p)",
+ static_cast<void*>(value_sp.get()),
+ static_cast<void*>(value_sp.get()));
+
return sb_value;
}
@@ -1487,8 +1585,9 @@ SBValue::GetLoadAddress()
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBValue(%p)::GetLoadAddress () => (%" PRIu64 ")", value_sp.get(), value);
-
+ log->Printf ("SBValue(%p)::GetLoadAddress () => (%" PRIu64 ")",
+ static_cast<void*>(value_sp.get()), value);
+
return value;
}
@@ -1524,8 +1623,11 @@ SBValue::GetAddress()
}
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBValue(%p)::GetAddress () => (%s,%" PRIu64 ")", value_sp.get(),
- (addr.GetSection() ? addr.GetSection()->GetName().GetCString() : "NULL"),
+ log->Printf ("SBValue(%p)::GetAddress () => (%s,%" PRIu64 ")",
+ static_cast<void*>(value_sp.get()),
+ (addr.GetSection()
+ ? addr.GetSection()->GetName().GetCString()
+ : "NULL"),
addr.GetOffset());
return SBAddress(new Address(addr));
}
@@ -1551,11 +1653,9 @@ SBValue::GetPointeeData (uint32_t item_idx,
}
if (log)
log->Printf ("SBValue(%p)::GetPointeeData (%d, %d) => SBData(%p)",
- value_sp.get(),
- item_idx,
- item_count,
- sb_data.get());
-
+ static_cast<void*>(value_sp.get()), item_idx, item_count,
+ static_cast<void*>(sb_data.get()));
+
return sb_data;
}
@@ -1569,15 +1669,16 @@ SBValue::GetData ()
if (value_sp)
{
DataExtractorSP data_sp(new DataExtractor());
- value_sp->GetData(*data_sp);
- if (data_sp->GetByteSize() > 0)
+ Error error;
+ value_sp->GetData(*data_sp, error);
+ if (error.Success())
*sb_data = data_sp;
}
if (log)
log->Printf ("SBValue(%p)::GetData () => SBData(%p)",
- value_sp.get(),
- sb_data.get());
-
+ static_cast<void*>(value_sp.get()),
+ static_cast<void*>(sb_data.get()));
+
return sb_data;
}
@@ -1588,25 +1689,26 @@ SBValue::SetData (lldb::SBData &data, SBError &error)
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
bool ret = true;
-
+
if (value_sp)
{
DataExtractor *data_extractor = data.get();
-
+
if (!data_extractor)
{
if (log)
- log->Printf ("SBValue(%p)::SetData() => error: no data to set", value_sp.get());
-
+ log->Printf ("SBValue(%p)::SetData() => error: no data to set",
+ static_cast<void*>(value_sp.get()));
+
error.SetErrorString("No data to set");
ret = false;
}
else
{
Error set_error;
-
+
value_sp->SetData(*data_extractor, set_error);
-
+
if (!set_error.Success())
{
error.SetErrorStringWithFormat("Couldn't set data: %s", set_error.AsCString());
@@ -1619,12 +1721,11 @@ SBValue::SetData (lldb::SBData &data, SBError &error)
error.SetErrorStringWithFormat ("Couldn't set data: could not get SBValue: %s", locker.GetError().AsCString());
ret = false;
}
-
+
if (log)
log->Printf ("SBValue(%p)::SetData (%p) => %s",
- value_sp.get(),
- data.get(),
- ret ? "true" : "false");
+ static_cast<void*>(value_sp.get()),
+ static_cast<void*>(data.get()), ret ? "true" : "false");
return ret;
}
@@ -1647,7 +1748,7 @@ lldb::SBWatchpoint
SBValue::Watch (bool resolve_location, bool read, bool write, SBError &error)
{
SBWatchpoint sb_watchpoint;
-
+
// If the SBValue is not valid, there's no point in even trying to watch it.
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
@@ -1657,29 +1758,29 @@ SBValue::Watch (bool resolve_location, bool read, bool write, SBError &error)
// Read and Write cannot both be false.
if (!read && !write)
return sb_watchpoint;
-
+
// If the value is not in scope, don't try and watch and invalid value
if (!IsInScope())
return sb_watchpoint;
-
+
addr_t addr = GetLoadAddress();
if (addr == LLDB_INVALID_ADDRESS)
return sb_watchpoint;
size_t byte_size = GetByteSize();
if (byte_size == 0)
return sb_watchpoint;
-
+
uint32_t watch_type = 0;
if (read)
watch_type |= LLDB_WATCH_TYPE_READ;
if (write)
watch_type |= LLDB_WATCH_TYPE_WRITE;
-
+
Error rc;
ClangASTType type (value_sp->GetClangType());
WatchpointSP watchpoint_sp = target_sp->CreateWatchpoint(addr, byte_size, &type, watch_type, rc);
error.SetError(rc);
-
+
if (watchpoint_sp)
{
sb_watchpoint.SetSP (watchpoint_sp);
@@ -1700,18 +1801,21 @@ SBValue::Watch (bool resolve_location, bool read, bool write, SBError &error)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBValue(%p)::Watch() => error getting SBValue: %s", value_sp.get(), locker.GetError().AsCString());
-
+ log->Printf ("SBValue(%p)::Watch() => error getting SBValue: %s",
+ static_cast<void*>(value_sp.get()),
+ locker.GetError().AsCString());
+
error.SetErrorStringWithFormat("could not get SBValue: %s", locker.GetError().AsCString());
}
else
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBValue(%p)::Watch() => error getting SBValue: no target", value_sp.get());
+ log->Printf ("SBValue(%p)::Watch() => error getting SBValue: no target",
+ static_cast<void*>(value_sp.get()));
error.SetErrorString("could not set watchpoint, a target is required");
}
-
+
return sb_watchpoint;
}
diff --git a/source/API/SBValueList.cpp b/source/API/SBValueList.cpp
index 46866eb37424..5069ed3f5624 100644
--- a/source/API/SBValueList.cpp
+++ b/source/API/SBValueList.cpp
@@ -99,8 +99,8 @@ SBValueList::SBValueList (const SBValueList &rhs) :
if (log)
{
log->Printf ("SBValueList::SBValueList (rhs.ap=%p) => this.ap = %p",
- (rhs.IsValid() ? rhs.m_opaque_ap.get() : NULL),
- m_opaque_ap.get());
+ static_cast<void*>(rhs.IsValid() ? rhs.m_opaque_ap.get() : NULL),
+ static_cast<void*>(m_opaque_ap.get()));
}
}
@@ -114,9 +114,9 @@ SBValueList::SBValueList (const ValueListImpl *lldb_object_ptr) :
if (log)
{
- log->Printf ("SBValueList::SBValueList (lldb_object_ptr=%p) => this.ap = %p",
- lldb_object_ptr,
- m_opaque_ap.get());
+ log->Printf ("SBValueList::SBValueList (lldb_object_ptr=%p) => this.ap = %p",
+ static_cast<const void*>(lldb_object_ptr),
+ static_cast<void*>(m_opaque_ap.get()));
}
}
@@ -218,7 +218,8 @@ SBValueList::GetValueAtIndex (uint32_t idx) const
SBStream sstr;
sb_value.GetDescription (sstr);
log->Printf ("SBValueList::GetValueAtIndex (this.ap=%p, idx=%d) => SBValue (this.sp = %p, '%s')",
- m_opaque_ap.get(), idx, sb_value.GetSP().get(), sstr.GetData());
+ static_cast<void*>(m_opaque_ap.get()), idx,
+ static_cast<void*>(sb_value.GetSP().get()), sstr.GetData());
}
return sb_value;
@@ -237,7 +238,8 @@ SBValueList::GetSize () const
size = m_opaque_ap->GetSize();
if (log)
- log->Printf ("SBValueList::GetSize (this.ap=%p) => %d", m_opaque_ap.get(), size);
+ log->Printf ("SBValueList::GetSize (this.ap=%p) => %d",
+ static_cast<void*>(m_opaque_ap.get()), size);
return size;
}
diff --git a/source/API/SBWatchpoint.cpp b/source/API/SBWatchpoint.cpp
index 194695c31d5b..1a1a970aaa87 100644
--- a/source/API/SBWatchpoint.cpp
+++ b/source/API/SBWatchpoint.cpp
@@ -42,7 +42,9 @@ SBWatchpoint::SBWatchpoint (const lldb::WatchpointSP &wp_sp) :
SBStream sstr;
GetDescription (sstr, lldb::eDescriptionLevelBrief);
log->Printf ("SBWatchpoint::SBWatchpoint (const lldb::WatchpointSP &wp_sp"
- "=%p) => this.sp = %p (%s)", wp_sp.get(), m_opaque_sp.get(), sstr.GetData());
+ "=%p) => this.sp = %p (%s)",
+ static_cast<void*>(wp_sp.get()),
+ static_cast<void*>(m_opaque_sp.get()), sstr.GetData());
}
}
@@ -77,9 +79,11 @@ SBWatchpoint::GetID ()
if (log)
{
if (watch_id == LLDB_INVALID_WATCH_ID)
- log->Printf ("SBWatchpoint(%p)::GetID () => LLDB_INVALID_WATCH_ID", watchpoint_sp.get());
+ log->Printf ("SBWatchpoint(%p)::GetID () => LLDB_INVALID_WATCH_ID",
+ static_cast<void*>(watchpoint_sp.get()));
else
- log->Printf ("SBWatchpoint(%p)::GetID () => %u", watchpoint_sp.get(), watch_id);
+ log->Printf ("SBWatchpoint(%p)::GetID () => %u",
+ static_cast<void*>(watchpoint_sp.get()), watch_id);
}
return watch_id;
@@ -185,7 +189,8 @@ SBWatchpoint::GetHitCount ()
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
- log->Printf ("SBWatchpoint(%p)::GetHitCount () => %u", watchpoint_sp.get(), count);
+ log->Printf ("SBWatchpoint(%p)::GetHitCount () => %u",
+ static_cast<void*>(watchpoint_sp.get()), count);
return count;
}
diff --git a/source/Breakpoint/Breakpoint.cpp b/source/Breakpoint/Breakpoint.cpp
index 5ce064fc41a0..7d08170e4aed 100644
--- a/source/Breakpoint/Breakpoint.cpp
+++ b/source/Breakpoint/Breakpoint.cpp
@@ -541,7 +541,7 @@ Breakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_l
if (!m_kind_description.empty())
{
- if (eDescriptionLevelBrief)
+ if (level == eDescriptionLevelBrief)
{
s->PutCString (GetBreakpointKind());
return;
diff --git a/source/Breakpoint/BreakpointID.cpp b/source/Breakpoint/BreakpointID.cpp
index 9a59e29d007d..9963ed68303a 100644
--- a/source/Breakpoint/BreakpointID.cpp
+++ b/source/Breakpoint/BreakpointID.cpp
@@ -71,7 +71,7 @@ void
BreakpointID::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == eDescriptionLevelVerbose)
- s->Printf("%p BreakpointID:", this);
+ s->Printf("%p BreakpointID:", static_cast<void*>(this));
if (m_break_id == LLDB_INVALID_BREAK_ID)
s->PutCString ("<invalid>");
diff --git a/source/Breakpoint/BreakpointList.cpp b/source/Breakpoint/BreakpointList.cpp
index 147ad36b0407..650737761547 100644
--- a/source/Breakpoint/BreakpointList.cpp
+++ b/source/Breakpoint/BreakpointList.cpp
@@ -167,7 +167,7 @@ void
BreakpointList::Dump (Stream *s) const
{
Mutex::Locker locker(m_mutex);
- s->Printf("%p: ", this);
+ s->Printf("%p: ", static_cast<const void*>(this));
s->Indent();
s->Printf("BreakpointList with %u Breakpoints:\n", (uint32_t)m_breakpoints.size());
s->IndentMore();
diff --git a/source/Breakpoint/BreakpointLocation.cpp b/source/Breakpoint/BreakpointLocation.cpp
index 2c75a11e9788..e1ac043ae905 100644
--- a/source/Breakpoint/BreakpointLocation.cpp
+++ b/source/Breakpoint/BreakpointLocation.cpp
@@ -289,7 +289,8 @@ BreakpointLocation::ConditionSaysStop (ExecutionContext &exe_ctx, Error &error)
if (!m_user_expression_sp->Parse(errors,
exe_ctx,
eExecutionPolicyOnlyWhenNeeded,
- true))
+ true,
+ false))
{
error.SetErrorStringWithFormat("Couldn't parse conditional expression:\n%s",
errors.GetData());
@@ -316,7 +317,7 @@ BreakpointLocation::ConditionSaysStop (ExecutionContext &exe_ctx, Error &error)
ClangExpressionVariableSP result_variable_sp;
- ExecutionResults result_code =
+ ExpressionResults result_code =
m_user_expression_sp->Execute(execution_errors,
exe_ctx,
options,
@@ -325,11 +326,10 @@ BreakpointLocation::ConditionSaysStop (ExecutionContext &exe_ctx, Error &error)
bool ret;
- if (result_code == eExecutionCompleted)
+ if (result_code == eExpressionCompleted)
{
if (!result_variable_sp)
{
- ret = false;
error.SetErrorString("Expression did not return a result");
return false;
}
@@ -522,8 +522,15 @@ BreakpointLocation::ClearBreakpointSite ()
{
if (m_bp_site_sp.get())
{
- m_owner.GetTarget().GetProcessSP()->RemoveOwnerFromBreakpointSite (GetBreakpoint().GetID(),
+ ProcessSP process_sp(m_owner.GetTarget().GetProcessSP());
+ // If the process exists, get it to remove the owner, it will remove the physical implementation
+ // of the breakpoint as well if there are no more owners. Otherwise just remove this owner.
+ if (process_sp)
+ process_sp->RemoveOwnerFromBreakpointSite (GetBreakpoint().GetID(),
GetID(), m_bp_site_sp);
+ else
+ m_bp_site_sp->RemoveOwner(GetBreakpoint().GetID(), GetID());
+
m_bp_site_sp.reset();
return true;
}
@@ -627,7 +634,7 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level)
if (exe_scope == NULL)
exe_scope = target;
- if (eDescriptionLevelInitial)
+ if (level == eDescriptionLevelInitial)
m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
else
m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress);
diff --git a/source/Breakpoint/BreakpointLocationList.cpp b/source/Breakpoint/BreakpointLocationList.cpp
index 917c776e75d2..ae7f863ad090 100644
--- a/source/Breakpoint/BreakpointLocationList.cpp
+++ b/source/Breakpoint/BreakpointLocationList.cpp
@@ -152,7 +152,7 @@ BreakpointLocationList::FindByAddress (const Address &addr) const
void
BreakpointLocationList::Dump (Stream *s) const
{
- s->Printf("%p: ", this);
+ s->Printf("%p: ", static_cast<const void*>(this));
//s->Indent();
Mutex::Locker locker (m_mutex);
s->Printf("BreakpointLocationList with %" PRIu64 " BreakpointLocations:\n", (uint64_t)m_locations.size());
diff --git a/source/Breakpoint/BreakpointOptions.cpp b/source/Breakpoint/BreakpointOptions.cpp
index 3a4a117695fc..ea8556d0930b 100644
--- a/source/Breakpoint/BreakpointOptions.cpp
+++ b/source/Breakpoint/BreakpointOptions.cpp
@@ -154,7 +154,7 @@ BreakpointOptions::InvokeCallback (StoppointCallbackContext *context,
}
bool
-BreakpointOptions::HasCallback ()
+BreakpointOptions::HasCallback () const
{
return m_callback != BreakpointOptions::NullCallback;
}
diff --git a/source/Breakpoint/BreakpointResolverName.cpp b/source/Breakpoint/BreakpointResolverName.cpp
index cf5d89cb7a8b..3ac3ed06fc70 100644
--- a/source/Breakpoint/BreakpointResolverName.cpp
+++ b/source/Breakpoint/BreakpointResolverName.cpp
@@ -234,7 +234,7 @@ BreakpointResolverName::SearchCallback
if (context.module_sp)
{
context.module_sp->FindFunctions (m_regex,
- !filter_by_cu, // include symbols only if we aren't filterning by CU
+ !filter_by_cu, // include symbols only if we aren't filtering by CU
include_inlines,
append,
func_list);
@@ -264,7 +264,7 @@ BreakpointResolverName::SearchCallback
}
}
- // Remove any duplicates between the funcion list and the symbol list
+ // Remove any duplicates between the function list and the symbol list
SymbolContext sc;
if (func_list.GetSize())
{
diff --git a/source/Breakpoint/BreakpointSite.cpp b/source/Breakpoint/BreakpointSite.cpp
index fa5d8c1f9f81..3cf6d37af379 100644
--- a/source/Breakpoint/BreakpointSite.cpp
+++ b/source/Breakpoint/BreakpointSite.cpp
@@ -32,7 +32,8 @@ BreakpointSite::BreakpointSite
m_saved_opcode(),
m_trap_opcode(),
m_enabled(false), // Need to create it disabled, so the first enable turns it on.
- m_owners()
+ m_owners(),
+ m_owners_mutex(Mutex::eMutexTypeRecursive)
{
m_owners.Add(owner);
}
@@ -60,6 +61,7 @@ BreakpointSite::GetNextID()
bool
BreakpointSite::ShouldStop (StoppointCallbackContext *context)
{
+ Mutex::Locker locker(m_owners_mutex);
IncrementHitCount();
return m_owners.ShouldStop (context);
}
@@ -67,6 +69,7 @@ BreakpointSite::ShouldStop (StoppointCallbackContext *context)
bool
BreakpointSite::IsBreakpointAtThisSite (lldb::break_id_t bp_id)
{
+ Mutex::Locker locker(m_owners_mutex);
const size_t owner_count = m_owners.GetSize();
for (size_t i = 0; i < owner_count; i++)
{
@@ -93,6 +96,7 @@ BreakpointSite::Dump(Stream *s) const
void
BreakpointSite::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
+ Mutex::Locker locker(m_owners_mutex);
if (level != lldb::eDescriptionLevelBrief)
s->Printf ("breakpoint site: %d at 0x%8.8" PRIx64, GetID(), GetLoadAddress());
m_owners.GetDescription (s, level);
@@ -162,12 +166,14 @@ BreakpointSite::SetEnabled (bool enabled)
void
BreakpointSite::AddOwner (const BreakpointLocationSP &owner)
{
+ Mutex::Locker locker(m_owners_mutex);
m_owners.Add(owner);
}
size_t
BreakpointSite::RemoveOwner (lldb::break_id_t break_id, lldb::break_id_t break_loc_id)
{
+ Mutex::Locker locker(m_owners_mutex);
m_owners.Remove(break_id, break_loc_id);
return m_owners.GetSize();
}
@@ -175,18 +181,21 @@ BreakpointSite::RemoveOwner (lldb::break_id_t break_id, lldb::break_id_t break_l
size_t
BreakpointSite::GetNumberOfOwners ()
{
+ Mutex::Locker locker(m_owners_mutex);
return m_owners.GetSize();
}
BreakpointLocationSP
BreakpointSite::GetOwnerAtIndex (size_t index)
{
+ Mutex::Locker locker(m_owners_mutex);
return m_owners.GetByIndex (index);
}
bool
BreakpointSite::ValidForThisThread (Thread *thread)
{
+ Mutex::Locker locker(m_owners_mutex);
return m_owners.ValidForThisThread(thread);
}
diff --git a/source/Breakpoint/BreakpointSiteList.cpp b/source/Breakpoint/BreakpointSiteList.cpp
index 68c4af18ec5e..1eaadb62a384 100644
--- a/source/Breakpoint/BreakpointSiteList.cpp
+++ b/source/Breakpoint/BreakpointSiteList.cpp
@@ -186,7 +186,7 @@ BreakpointSiteList::BreakpointSiteContainsBreakpoint (lldb::break_id_t bp_site_i
void
BreakpointSiteList::Dump (Stream *s) const
{
- s->Printf("%p: ", this);
+ s->Printf("%p: ", static_cast<const void*>(this));
//s->Indent();
s->Printf("BreakpointSiteList with %u BreakpointSites:\n", (uint32_t)m_bp_site_list.size());
s->IndentMore();
diff --git a/source/Breakpoint/WatchpointList.cpp b/source/Breakpoint/WatchpointList.cpp
index 6d62dffd22cc..472bae06b441 100644
--- a/source/Breakpoint/WatchpointList.cpp
+++ b/source/Breakpoint/WatchpointList.cpp
@@ -55,7 +55,7 @@ void
WatchpointList::DumpWithLevel (Stream *s, lldb::DescriptionLevel description_level) const
{
Mutex::Locker locker (m_mutex);
- s->Printf("%p: ", this);
+ s->Printf("%p: ", static_cast<const void*>(this));
//s->Indent();
s->Printf("WatchpointList with %" PRIu64 " Watchpoints:\n",
(uint64_t)m_watchpoints.size());
diff --git a/source/Commands/CommandCompletions.cpp b/source/Commands/CommandCompletions.cpp
index 970aa692bd27..f0ad4a896739 100644
--- a/source/Commands/CommandCompletions.cpp
+++ b/source/Commands/CommandCompletions.cpp
@@ -30,6 +30,8 @@
#include "lldb/Target/Target.h"
#include "lldb/Utility/CleanUp.h"
+#include "llvm/ADT/SmallString.h"
+
using namespace lldb_private;
CommandCompletions::CommonCompletionElement
@@ -221,7 +223,7 @@ DiskFilesOrDirectories
end_ptr = strrchr(partial_name_copy, '/');
// This will store the resolved form of the containing directory
- char containing_part[PATH_MAX];
+ llvm::SmallString<64> containing_part;
if (end_ptr == NULL)
{
@@ -232,14 +234,11 @@ DiskFilesOrDirectories
// Nothing here but the user name. We could just put a slash on the end,
// but for completeness sake we'll resolve the user name and only put a slash
// on the end if it exists.
- char resolved_username[PATH_MAX];
- size_t resolved_username_len = FileSpec::ResolveUsername (partial_name_copy, resolved_username,
- sizeof (resolved_username));
+ llvm::SmallString<64> resolved_username(partial_name_copy);
+ FileSpec::ResolveUsername (resolved_username);
// Not sure how this would happen, a username longer than PATH_MAX? Still...
- if (resolved_username_len >= sizeof (resolved_username))
- return matches.GetSize();
- else if (resolved_username_len == 0)
+ if (resolved_username.size() == 0)
{
// The user name didn't resolve, let's look in the password database for matches.
// The user name database contains duplicates, and is not in alphabetical order, so
@@ -263,8 +262,7 @@ DiskFilesOrDirectories
else
{
// The containing part is the CWD, and the whole string is the remainder.
- containing_part[0] = '.';
- containing_part[1] = '\0';
+ containing_part = ".";
strcpy(remainder, partial_name_copy);
end_ptr = partial_name_copy;
}
@@ -274,14 +272,11 @@ DiskFilesOrDirectories
if (end_ptr == partial_name_copy)
{
// We're completing a file or directory in the root volume.
- containing_part[0] = '/';
- containing_part[1] = '\0';
+ containing_part = "/";
}
else
{
- size_t len = end_ptr - partial_name_copy;
- memcpy(containing_part, partial_name_copy, len);
- containing_part[len] = '\0';
+ containing_part.append(partial_name_copy, end_ptr);
}
// Push end_ptr past the final "/" and set remainder.
end_ptr++;
@@ -293,11 +288,9 @@ DiskFilesOrDirectories
if (*partial_name_copy == '~')
{
- size_t resolved_username_len = FileSpec::ResolveUsername(containing_part,
- containing_part,
- sizeof (containing_part));
+ FileSpec::ResolveUsername(containing_part);
// User name doesn't exist, we're not getting any further...
- if (resolved_username_len == 0 || resolved_username_len >= sizeof (containing_part))
+ if (containing_part.empty())
return matches.GetSize();
}
@@ -314,7 +307,7 @@ DiskFilesOrDirectories
parameters.end_ptr = end_ptr;
parameters.baselen = baselen;
- FileSpec::EnumerateDirectory(containing_part, true, true, true, DiskFilesOrDirectoriesCallback, &parameters);
+ FileSpec::EnumerateDirectory(containing_part.c_str(), true, true, true, DiskFilesOrDirectoriesCallback, &parameters);
return matches.GetSize();
}
diff --git a/source/Commands/CommandObjectArgs.cpp b/source/Commands/CommandObjectArgs.cpp
index 3b919d11a566..b0fe42bc2446 100644
--- a/source/Commands/CommandObjectArgs.cpp
+++ b/source/Commands/CommandObjectArgs.cpp
@@ -57,13 +57,7 @@ CommandObjectArgs::CommandOptions::SetOptionValue (uint32_t option_idx, const ch
Error error;
const int short_option = m_getopt_table[option_idx].val;
-
- switch (short_option)
- {
- default:
- error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
- break;
- }
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
return error;
}
@@ -255,7 +249,7 @@ CommandObjectArgs::DoExecute (Args& args, CommandReturnObject &result)
for (arg_index = 0; arg_index < num_args; ++arg_index)
{
- result.GetOutputStream ().Printf ("%zu (%s): ", arg_index, args.GetArgumentAtIndex (arg_index));
+ result.GetOutputStream ().Printf ("%" PRIu64 " (%s): ", (uint64_t)arg_index, args.GetArgumentAtIndex (arg_index));
value_list.GetValueAtIndex (arg_index)->Dump (&result.GetOutputStream ());
result.GetOutputStream ().Printf("\n");
}
@@ -266,7 +260,7 @@ CommandObjectArgs::DoExecute (Args& args, CommandReturnObject &result)
OptionDefinition
CommandObjectArgs::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "debug", 'g', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Enable verbose debug logging of the expression parsing and evaluation."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_1, false, "debug", 'g', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Enable verbose debug logging of the expression parsing and evaluation."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
diff --git a/source/Commands/CommandObjectBreakpoint.cpp b/source/Commands/CommandObjectBreakpoint.cpp
index c20da7f3ec5c..13bf1278c78c 100644
--- a/source/Commands/CommandObjectBreakpoint.cpp
+++ b/source/Commands/CommandObjectBreakpoint.cpp
@@ -154,9 +154,12 @@ public:
case eLanguageTypeC89:
case eLanguageTypeC:
case eLanguageTypeC99:
+ case eLanguageTypeC11:
m_language = eLanguageTypeC;
break;
case eLanguageTypeC_plus_plus:
+ case eLanguageTypeC_plus_plus_03:
+ case eLanguageTypeC_plus_plus_11:
m_language = eLanguageTypeC_plus_plus;
break;
case eLanguageTypeObjC:
@@ -623,41 +626,41 @@ private:
OptionDefinition
CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_NOT_10, false, "shlib", 's', OptionParser::eRequiredArgument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName,
+ { LLDB_OPT_NOT_10, false, "shlib", 's', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName,
"Set the breakpoint only in this shared library. "
"Can repeat this option multiple times to specify multiple shared libraries."},
- { LLDB_OPT_SET_ALL, false, "ignore-count", 'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount,
+ { LLDB_OPT_SET_ALL, false, "ignore-count", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCount,
"Set the number of times this breakpoint is skipped before stopping." },
- { LLDB_OPT_SET_ALL, false, "one-shot", 'o', OptionParser::eNoArgument, NULL, 0, eArgTypeNone,
+ { LLDB_OPT_SET_ALL, false, "one-shot", 'o', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
"The breakpoint is deleted the first time it causes a stop." },
- { LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeExpression,
+ { LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeExpression,
"The breakpoint stops only if this condition expression evaluates to true."},
- { LLDB_OPT_SET_ALL, false, "thread-index", 'x', OptionParser::eRequiredArgument, NULL, 0, eArgTypeThreadIndex,
+ { LLDB_OPT_SET_ALL, false, "thread-index", 'x', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadIndex,
"The breakpoint stops only for the thread whose indeX matches this argument."},
- { LLDB_OPT_SET_ALL, false, "thread-id", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeThreadID,
+ { LLDB_OPT_SET_ALL, false, "thread-id", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadID,
"The breakpoint stops only for the thread whose TID matches this argument."},
- { LLDB_OPT_SET_ALL, false, "thread-name", 'T', OptionParser::eRequiredArgument, NULL, 0, eArgTypeThreadName,
+ { LLDB_OPT_SET_ALL, false, "thread-name", 'T', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadName,
"The breakpoint stops only for the thread whose thread name matches this argument."},
- { LLDB_OPT_SET_ALL, false, "hardware", 'H', OptionParser::eNoArgument, NULL, 0, eArgTypeNone,
+ { LLDB_OPT_SET_ALL, false, "hardware", 'H', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
"Require the breakpoint to use hardware breakpoints."},
- { LLDB_OPT_SET_ALL, false, "queue-name", 'q', OptionParser::eRequiredArgument, NULL, 0, eArgTypeQueueName,
+ { LLDB_OPT_SET_ALL, false, "queue-name", 'q', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeQueueName,
"The breakpoint stops only for threads in the queue whose name is given by this argument."},
- { LLDB_OPT_FILE, false, "file", 'f', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
+ { LLDB_OPT_FILE, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
"Specifies the source file in which to set this breakpoint. "
"Note, by default lldb only looks for files that are #included if they use the standard include file extensions. "
"To set breakpoints on .c/.cpp/.m/.mm files that are #included, set target.inline-breakpoint-strategy"
" to \"always\"."},
- { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeLineNum,
+ { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLineNum,
"Specifies the line number on which to set this breakpoint."},
// Comment out this option for the moment, as we don't actually use it, but will in the future.
@@ -665,48 +668,48 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
// { 0, false, "column", 'C', OptionParser::eRequiredArgument, NULL, "<column>",
// "Set the breakpoint by source location at this particular column."},
- { LLDB_OPT_SET_2, true, "address", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeAddressOrExpression,
+ { LLDB_OPT_SET_2, true, "address", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeAddressOrExpression,
"Set the breakpoint by address, at the specified address."},
- { LLDB_OPT_SET_3, true, "name", 'n', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
+ { LLDB_OPT_SET_3, true, "name", 'n', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
"Set the breakpoint by function name. Can be repeated multiple times to make one breakpoint for multiple names" },
- { LLDB_OPT_SET_4, true, "fullname", 'F', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFullName,
+ { LLDB_OPT_SET_4, true, "fullname", 'F', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFullName,
"Set the breakpoint by fully qualified function names. For C++ this means namespaces and all arguments, and "
"for Objective C this means a full function prototype with class and selector. "
"Can be repeated multiple times to make one breakpoint for multiple names." },
- { LLDB_OPT_SET_5, true, "selector", 'S', OptionParser::eRequiredArgument, NULL, 0, eArgTypeSelector,
+ { LLDB_OPT_SET_5, true, "selector", 'S', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeSelector,
"Set the breakpoint by ObjC selector name. Can be repeated multiple times to make one breakpoint for multiple Selectors." },
- { LLDB_OPT_SET_6, true, "method", 'M', OptionParser::eRequiredArgument, NULL, 0, eArgTypeMethod,
+ { LLDB_OPT_SET_6, true, "method", 'M', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeMethod,
"Set the breakpoint by C++ method names. Can be repeated multiple times to make one breakpoint for multiple methods." },
- { LLDB_OPT_SET_7, true, "func-regex", 'r', OptionParser::eRequiredArgument, NULL, 0, eArgTypeRegularExpression,
+ { LLDB_OPT_SET_7, true, "func-regex", 'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression,
"Set the breakpoint by function name, evaluating a regular-expression to find the function name(s)." },
- { LLDB_OPT_SET_8, true, "basename", 'b', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
+ { LLDB_OPT_SET_8, true, "basename", 'b', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
"Set the breakpoint by function basename (C++ namespaces and arguments will be ignored). "
"Can be repeated multiple times to make one breakpoint for multiple symbols." },
- { LLDB_OPT_SET_9, true, "source-pattern-regexp", 'p', OptionParser::eRequiredArgument, NULL, 0, eArgTypeRegularExpression,
+ { LLDB_OPT_SET_9, true, "source-pattern-regexp", 'p', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression,
"Set the breakpoint by specifying a regular expression which is matched against the source text in a source file or files "
"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_10, true, "language-exception", 'E', OptionParser::eRequiredArgument, NULL, 0, eArgTypeLanguage,
+ { 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.)" },
- { LLDB_OPT_SET_10, false, "on-throw", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean,
+ { LLDB_OPT_SET_10, false, "on-throw", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,
"Set the breakpoint on exception throW." },
- { LLDB_OPT_SET_10, false, "on-catch", 'h', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean,
+ { LLDB_OPT_SET_10, false, "on-catch", 'h', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,
"Set the breakpoint on exception catcH." },
- { LLDB_OPT_SKIP_PROLOGUE, false, "skip-prologue", 'K', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean,
+ { 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." },
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -1012,16 +1015,16 @@ private:
OptionDefinition
CommandObjectBreakpointModify::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_ALL, false, "ignore-count", 'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount, "Set the number of times this breakpoint is skipped before stopping." },
-{ LLDB_OPT_SET_ALL, false, "one-shot", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "The breakpoint is deleted the first time it stop causes a stop." },
-{ LLDB_OPT_SET_ALL, false, "thread-index", 'x', OptionParser::eRequiredArgument, NULL, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose index matches this argument."},
-{ LLDB_OPT_SET_ALL, false, "thread-id", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeThreadID, "The breakpoint stops only for the thread whose TID matches this argument."},
-{ LLDB_OPT_SET_ALL, false, "thread-name", 'T', OptionParser::eRequiredArgument, NULL, 0, eArgTypeThreadName, "The breakpoint stops only for the thread whose thread name matches this argument."},
-{ LLDB_OPT_SET_ALL, false, "queue-name", 'q', OptionParser::eRequiredArgument, NULL, 0, eArgTypeQueueName, "The breakpoint stops only for threads in the queue whose name is given by this argument."},
-{ LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true."},
-{ LLDB_OPT_SET_1, false, "enable", 'e', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Enable the breakpoint."},
-{ LLDB_OPT_SET_2, false, "disable", 'd', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Disable the breakpoint."},
-{ 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_ALL, false, "ignore-count", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCount, "Set the number of times this breakpoint is skipped before stopping." },
+{ LLDB_OPT_SET_ALL, false, "one-shot", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "The breakpoint is deleted the first time it stop causes a stop." },
+{ LLDB_OPT_SET_ALL, false, "thread-index", 'x', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose index matches this argument."},
+{ LLDB_OPT_SET_ALL, false, "thread-id", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadID, "The breakpoint stops only for the thread whose TID matches this argument."},
+{ LLDB_OPT_SET_ALL, false, "thread-name", 'T', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadName, "The breakpoint stops only for the thread whose thread name matches this argument."},
+{ LLDB_OPT_SET_ALL, false, "queue-name", 'q', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeQueueName, "The breakpoint stops only for threads in the queue whose name is given by this argument."},
+{ LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true."},
+{ LLDB_OPT_SET_1, false, "enable", 'e', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Enable the breakpoint."},
+{ LLDB_OPT_SET_2, false, "disable", 'd', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Disable the breakpoint."},
+{ 0, false, NULL, 0 , 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -1078,7 +1081,7 @@ protected:
{
// No breakpoint selected; enable all currently set breakpoints.
target->EnableAllBreakpoints ();
- result.AppendMessageWithFormat ("All breakpoints enabled. (%zu breakpoints)\n", num_breakpoints);
+ result.AppendMessageWithFormat ("All breakpoints enabled. (%" PRIu64 " breakpoints)\n", (uint64_t)num_breakpoints);
result.SetStatus (eReturnStatusSuccessFinishNoResult);
}
else
@@ -1197,7 +1200,7 @@ protected:
{
// No breakpoint selected; disable all currently set breakpoints.
target->DisableAllBreakpoints ();
- result.AppendMessageWithFormat ("All breakpoints disabled. (%zu breakpoints)\n", num_breakpoints);
+ result.AppendMessageWithFormat ("All breakpoints disabled. (%" PRIu64 " breakpoints)\n", (uint64_t)num_breakpoints);
result.SetStatus (eReturnStatusSuccessFinishNoResult);
}
else
@@ -1421,21 +1424,21 @@ private:
OptionDefinition
CommandObjectBreakpointList::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "internal", 'i', OptionParser::eNoArgument, NULL, 0, eArgTypeNone,
+ { LLDB_OPT_SET_ALL, false, "internal", 'i', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
"Show debugger internal breakpoints" },
- { LLDB_OPT_SET_1, false, "brief", 'b', OptionParser::eNoArgument, NULL, 0, eArgTypeNone,
+ { LLDB_OPT_SET_1, false, "brief", 'b', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
"Give a brief description of the breakpoint (no location info)."},
// FIXME: We need to add an "internal" command, and then add this sort of thing to it.
// But I need to see it for now, and don't want to wait.
- { LLDB_OPT_SET_2, false, "full", 'f', OptionParser::eNoArgument, NULL, 0, eArgTypeNone,
+ { LLDB_OPT_SET_2, false, "full", 'f', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
"Give a full description of the breakpoint and its locations."},
- { LLDB_OPT_SET_3, false, "verbose", 'v', OptionParser::eNoArgument, NULL, 0, eArgTypeNone,
+ { LLDB_OPT_SET_3, false, "verbose", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
"Explain everything we know about the breakpoint (for debugging debugger bugs)." },
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -1632,13 +1635,13 @@ private:
OptionDefinition
CommandObjectBreakpointClear::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
+ { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
"Specify the breakpoint by source location in this particular file."},
- { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeLineNum,
+ { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLineNum,
"Specify the breakpoint by source location at this particular line."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -1699,7 +1702,7 @@ protected:
else
{
target->RemoveAllBreakpoints ();
- result.AppendMessageWithFormat ("All breakpoints removed. (%zu %s)\n", num_breakpoints, num_breakpoints > 1 ? "breakpoints" : "breakpoint");
+ result.AppendMessageWithFormat ("All breakpoints removed. (%" PRIu64 " breakpoint%s)\n", (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : "");
}
result.SetStatus (eReturnStatusSuccessFinishNoResult);
}
@@ -1843,7 +1846,7 @@ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *targe
if (breakpoint != NULL)
{
const size_t num_locations = breakpoint->GetNumLocations();
- if (cur_bp_id.GetLocationID() > num_locations)
+ if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations)
{
StreamString id_str;
BreakpointID::GetCanonicalReference (&id_str,
diff --git a/source/Commands/CommandObjectBreakpointCommand.cpp b/source/Commands/CommandObjectBreakpointCommand.cpp
index 532d6cedc83e..fdb87d11900b 100644
--- a/source/Commands/CommandObjectBreakpointCommand.cpp
+++ b/source/Commands/CommandObjectBreakpointCommand.cpp
@@ -44,9 +44,10 @@ public:
CommandObjectBreakpointCommandAdd (CommandInterpreter &interpreter) :
CommandObjectParsed (interpreter,
"add",
- "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit.",
+ "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit."
+ " If no breakpoint is specified, adds the commands to the last created breakpoint.",
NULL),
- IOHandlerDelegateMultiline ("DONE", IOHandlerDelegate::Completion::LLDBCommand),
+ IOHandlerDelegateMultiline ("DONE", IOHandlerDelegate::Completion::LLDBCommand),
m_options (interpreter)
{
SetHelpLong (
@@ -193,7 +194,7 @@ one command per line.\n" );
// Define the first (and only) variant of this arg.
bp_id_arg.arg_type = eArgTypeBreakpointID;
- bp_id_arg.arg_repetition = eArgRepeatPlain;
+ bp_id_arg.arg_repetition = eArgRepeatOptional;
// There is only one variant this argument could be; put it into the argument entry.
arg.push_back (bp_id_arg);
@@ -228,9 +229,12 @@ one command per line.\n" );
{
io_handler.SetIsDone(true);
- BreakpointOptions *bp_options = (BreakpointOptions *) io_handler.GetUserData();
- if (bp_options)
+ std::vector<BreakpointOptions *> *bp_options_vec = (std::vector<BreakpointOptions *> *)io_handler.GetUserData();
+ for (BreakpointOptions *bp_options : *bp_options_vec)
{
+ if (!bp_options)
+ continue;
+
std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
if (data_ap.get())
{
@@ -239,36 +243,37 @@ one command per line.\n" );
bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
}
}
-
}
void
- CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec,
CommandReturnObject &result)
{
m_interpreter.GetLLDBCommandsFromIOHandler ("> ", // Prompt
*this, // IOHandlerDelegate
true, // Run IOHandler in async mode
- bp_options); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions
+ &bp_options_vec); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions
}
/// Set a one-liner as the callback for the breakpoint.
void
- SetBreakpointCommandCallback (BreakpointOptions *bp_options,
+ SetBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec,
const char *oneliner)
{
- std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
-
- // It's necessary to set both user_source and script_source to the oneliner.
- // The former is used to generate callback description (as in breakpoint command list)
- // while the latter is used for Python to interpret during the actual callback.
- data_ap->user_source.AppendString (oneliner);
- data_ap->script_source.assign (oneliner);
- data_ap->stop_on_error = m_options.m_stop_on_error;
+ for (auto bp_options : bp_options_vec)
+ {
+ std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
- BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
- bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
+ // It's necessary to set both user_source and script_source to the oneliner.
+ // The former is used to generate callback description (as in breakpoint command list)
+ // while the latter is used for Python to interpret during the actual callback.
+ data_ap->user_source.AppendString (oneliner);
+ data_ap->script_source.assign (oneliner);
+ data_ap->stop_on_error = m_options.m_stop_on_error;
+ BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
+ bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
+ }
return;
}
@@ -459,15 +464,11 @@ protected:
BreakpointIDList valid_bp_ids;
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+ m_bp_options_vec.clear();
+
if (result.Succeeded())
{
const size_t count = valid_bp_ids.GetSize();
- if (count > 1)
- {
- result.AppendError ("can only add commands to one breakpoint at a time.");
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
for (size_t i = 0; i < count; ++i)
{
@@ -489,50 +490,45 @@ protected:
if (bp_loc_sp)
bp_options = bp_loc_sp->GetLocationOptions();
}
+ if (bp_options)
+ m_bp_options_vec.push_back (bp_options);
+ }
+ }
- // Skip this breakpoint if bp_options is not good.
- if (bp_options == NULL) continue;
-
- // If we are using script language, get the script interpreter
- // in order to set or collect command callback. Otherwise, call
- // the methods associated with this object.
- if (m_options.m_use_script_language)
- {
- // Special handling for one-liner specified inline.
- if (m_options.m_use_one_liner)
- {
- m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
- m_options.m_one_liner.c_str());
- }
- // Special handling for using a Python function by name
- // instead of extending the breakpoint callback data structures, we just automatize
- // what the user would do manually: make their breakpoint command be a function call
- else if (m_options.m_function_name.size())
- {
- std::string oneliner("return ");
- oneliner += m_options.m_function_name;
- oneliner += "(frame, bp_loc, internal_dict)";
- m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
- oneliner.c_str());
- }
- else
- {
- m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options,
- result);
- }
- }
- else
- {
- // Special handling for one-liner specified inline.
- if (m_options.m_use_one_liner)
- SetBreakpointCommandCallback (bp_options,
- m_options.m_one_liner.c_str());
- else
- CollectDataForBreakpointCommandCallback (bp_options,
- result);
- }
+ // If we are using script language, get the script interpreter
+ // in order to set or collect command callback. Otherwise, call
+ // the methods associated with this object.
+ if (m_options.m_use_script_language)
+ {
+ ScriptInterpreter *script_interp = m_interpreter.GetScriptInterpreter();
+ // Special handling for one-liner specified inline.
+ if (m_options.m_use_one_liner)
+ {
+ script_interp->SetBreakpointCommandCallback (m_bp_options_vec,
+ m_options.m_one_liner.c_str());
+ }
+ else if (m_options.m_function_name.size())
+ {
+ script_interp->SetBreakpointCommandCallbackFunction (m_bp_options_vec,
+ m_options.m_function_name.c_str());
+ }
+ else
+ {
+ script_interp->CollectDataForBreakpointCommandCallback (m_bp_options_vec,
+ result);
}
}
+ else
+ {
+ // Special handling for one-liner specified inline.
+ if (m_options.m_use_one_liner)
+ SetBreakpointCommandCallback (m_bp_options_vec,
+ m_options.m_one_liner.c_str());
+ else
+ CollectDataForBreakpointCommandCallback (m_bp_options_vec,
+ result);
+ }
+
}
return result.Succeeded();
@@ -540,6 +536,17 @@ protected:
private:
CommandOptions m_options;
+ std::vector<BreakpointOptions *> m_bp_options_vec; // This stores the breakpoint options that we are currently
+ // collecting commands for. In the CollectData... calls we need
+ // to hand this off to the IOHandler, which may run asynchronously.
+ // So we have to have some way to keep it alive, and not leak it.
+ // Making it an ivar of the command object, which never goes away
+ // achieves this. Note that if we were able to run
+ // the same command concurrently in one interpreter we'd have to
+ // make this "per invocation". But there are many more reasons
+ // why it is not in general safe to do that in lldb at present,
+ // so it isn't worthwhile to come up with a more complex mechanism
+ // to address this particular weakness right now.
static const char *g_reader_instructions;
};
@@ -562,19 +569,19 @@ g_script_option_enumeration[4] =
OptionDefinition
CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOneLiner,
+ { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOneLiner,
"Specify a one-line breakpoint command inline. Be sure to surround it with quotes." },
- { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean,
+ { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,
"Specify whether breakpoint command execution should terminate on error." },
- { LLDB_OPT_SET_ALL, false, "script-type", 's', OptionParser::eRequiredArgument, g_script_option_enumeration, 0, eArgTypeNone,
+ { LLDB_OPT_SET_ALL, false, "script-type", 's', OptionParser::eRequiredArgument, NULL, g_script_option_enumeration, 0, eArgTypeNone,
"Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
- { LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, 0, eArgTypePythonFunction,
+ { LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction,
"Give the name of a Python function to run as command for this breakpoint. Be sure to give a module name if appropriate."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -814,7 +821,7 @@ protected:
CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
CommandObjectMultiword (interpreter,
"command",
- "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
+ "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commands').",
"command <sub-command> [<sub-command-options>] <breakpoint-id>")
{
CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter));
diff --git a/source/Commands/CommandObjectCommands.cpp b/source/Commands/CommandObjectCommands.cpp
index 7bfdec094d6c..7d9bb7dad8fd 100644
--- a/source/Commands/CommandObjectCommands.cpp
+++ b/source/Commands/CommandObjectCommands.cpp
@@ -226,11 +226,11 @@ protected:
OptionDefinition
CommandObjectCommandsHistory::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger, "How many history commands to print."},
-{ LLDB_OPT_SET_1, false, "start-index", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger, "Index at which to start printing history commands (or end to mean tail mode)."},
-{ LLDB_OPT_SET_1, false, "end-index", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger, "Index at which to stop printing history commands."},
-{ LLDB_OPT_SET_2, false, "clear", 'C', OptionParser::eNoArgument, NULL, 0, eArgTypeBoolean, "Clears the current command history."},
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger, "How many history commands to print."},
+{ LLDB_OPT_SET_1, false, "start-index", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger, "Index at which to start printing history commands (or end to mean tail mode)."},
+{ LLDB_OPT_SET_1, false, "end-index", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger, "Index at which to stop printing history commands."},
+{ LLDB_OPT_SET_2, false, "clear", 'C', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeBoolean, "Clears the current command history."},
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -427,10 +427,10 @@ protected:
OptionDefinition
CommandObjectCommandsSource::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on error."},
-{ LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on continue."},
-{ LLDB_OPT_SET_ALL, false, "silent-run", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "If true don't echo commands while executing."},
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on error."},
+{ LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on continue."},
+{ LLDB_OPT_SET_ALL, false, "silent-run", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "If true don't echo commands while executing."},
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#pragma mark CommandObjectCommandsAlias
@@ -889,7 +889,7 @@ public:
SetHelpLong(
"This command allows the user to create powerful regular expression commands\n"
"with substitutions. The regular expressions and substitutions are specified\n"
-"using the regular exression substitution format of:\n"
+"using the regular expression substitution format of:\n"
"\n"
" s/<regex>/<subst>/\n"
"\n"
@@ -1034,9 +1034,10 @@ protected:
Debugger &debugger = m_interpreter.GetDebugger();
const bool multiple_lines = true; // Get multiple lines
IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
- "lldb", // Name of input reader for history
- "\033[K> ", // Prompt and clear line
+ "lldb-regex", // Name of input reader for history
+ "\033[K> ", // Prompt and clear line
multiple_lines,
+ 0, // Don't show line numbers
*this));
if (io_handler_sp)
@@ -1273,9 +1274,9 @@ private:
OptionDefinition
CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNone, "The help text to display for this command."},
-{ LLDB_OPT_SET_1, false, "syntax", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."},
-{ 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeNone, "The help text to display for this command."},
+{ LLDB_OPT_SET_1, false, "syntax", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."},
+{ 0 , false, NULL , 0 , 0 , NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -1547,8 +1548,8 @@ protected:
OptionDefinition
CommandObjectCommandsScriptImport::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "allow-reload", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Allow the script to be loaded even if it was already loaded before. This argument exists for backwards compatibility, but reloading is always allowed, whether you specify it or not."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_1, false, "allow-reload", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Allow the script to be loaded even if it was already loaded before. This argument exists for backwards compatibility, but reloading is always allowed, whether you specify it or not."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -1795,9 +1796,9 @@ static OptionEnumValueElement g_script_synchro_type[] =
OptionDefinition
CommandObjectCommandsScriptAdd::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "function", 'f', OptionParser::eRequiredArgument, NULL, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name."},
- { LLDB_OPT_SET_1, false, "synchronicity", 's', OptionParser::eRequiredArgument, 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, 0, eArgTypeNone, NULL }
+ { 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_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."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
diff --git a/source/Commands/CommandObjectDisassemble.cpp b/source/Commands/CommandObjectDisassemble.cpp
index f9c683b364ce..8124ce1ef93b 100644
--- a/source/Commands/CommandObjectDisassemble.cpp
+++ b/source/Commands/CommandObjectDisassemble.cpp
@@ -232,29 +232,29 @@ CommandObjectDisassemble::CommandOptions::GetDefinitions ()
OptionDefinition
CommandObjectDisassemble::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_ALL, false, "bytes" , 'b', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "Show opcode bytes when disassembling."},
-{ LLDB_OPT_SET_ALL, false, "context" , 'C', OptionParser::eRequiredArgument , NULL, 0, eArgTypeNumLines, "Number of context lines of source to show."},
-{ LLDB_OPT_SET_ALL, false, "mixed" , 'm', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "Enable mixed source and assembly display."},
-{ LLDB_OPT_SET_ALL, false, "raw" , 'r', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "Print raw disassembly with no symbol information."},
-{ LLDB_OPT_SET_ALL, false, "plugin" , 'P', OptionParser::eRequiredArgument , NULL, 0, eArgTypePlugin, "Name of the disassembler plugin you want to use."},
-{ LLDB_OPT_SET_ALL, false, "flavor" , 'F', OptionParser::eRequiredArgument , NULL, 0, eArgTypeDisassemblyFlavor, "Name of the disassembly flavor you want to use. "
- "Currently the only valid options are default, and for Intel"
- " architectures, att and intel."},
-{ LLDB_OPT_SET_ALL, false, "arch" , 'A', OptionParser::eRequiredArgument , NULL, 0, eArgTypeArchitecture,"Specify the architecture to use from cross disassembly."},
+{ LLDB_OPT_SET_ALL, false, "bytes" , 'b', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Show opcode bytes when disassembling."},
+{ LLDB_OPT_SET_ALL, false, "context" , 'C', OptionParser::eRequiredArgument , NULL, NULL, 0, eArgTypeNumLines, "Number of context lines of source to show."},
+{ LLDB_OPT_SET_ALL, false, "mixed" , 'm', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Enable mixed source and assembly display."},
+{ LLDB_OPT_SET_ALL, false, "raw" , 'r', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Print raw disassembly with no symbol information."},
+{ LLDB_OPT_SET_ALL, false, "plugin" , 'P', OptionParser::eRequiredArgument , NULL, NULL, 0, eArgTypePlugin, "Name of the disassembler plugin you want to use."},
+{ LLDB_OPT_SET_ALL, false, "flavor" , 'F', OptionParser::eRequiredArgument , NULL, NULL, 0, eArgTypeDisassemblyFlavor, "Name of the disassembly flavor you want to use. "
+ "Currently the only valid options are default, and for Intel"
+ " architectures, att and intel."},
+{ LLDB_OPT_SET_ALL, false, "arch" , 'A', OptionParser::eRequiredArgument , NULL, NULL, 0, eArgTypeArchitecture,"Specify the architecture to use from cross disassembly."},
{ LLDB_OPT_SET_1 |
- LLDB_OPT_SET_2 , true , "start-address", 's', OptionParser::eRequiredArgument , NULL, 0, eArgTypeAddressOrExpression,"Address at which to start disassembling."},
-{ LLDB_OPT_SET_1 , false, "end-address" , 'e', OptionParser::eRequiredArgument , NULL, 0, eArgTypeAddressOrExpression, "Address at which to end disassembling."},
+ LLDB_OPT_SET_2 , true , "start-address", 's', OptionParser::eRequiredArgument , NULL, NULL, 0, eArgTypeAddressOrExpression,"Address at which to start disassembling."},
+{ LLDB_OPT_SET_1 , false, "end-address" , 'e', OptionParser::eRequiredArgument , NULL, NULL, 0, eArgTypeAddressOrExpression, "Address at which to end disassembling."},
{ LLDB_OPT_SET_2 |
LLDB_OPT_SET_3 |
LLDB_OPT_SET_4 |
- LLDB_OPT_SET_5 , false, "count" , 'c', OptionParser::eRequiredArgument , NULL, 0, eArgTypeNumLines, "Number of instructions to display."},
-{ LLDB_OPT_SET_3 , false, "name" , 'n', OptionParser::eRequiredArgument , NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
- "Disassemble entire contents of the given function name."},
-{ LLDB_OPT_SET_4 , false, "frame" , 'f', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "Disassemble from the start of the current frame's function."},
-{ LLDB_OPT_SET_5 , false, "pc" , 'p', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "Disassemble around the current pc."},
-{ LLDB_OPT_SET_6 , false, "line" , 'l', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "Disassemble the current frame's current source line instructions if there is debug line table information, else disassemble around the pc."},
-{ LLDB_OPT_SET_7 , false, "address" , 'a', OptionParser::eRequiredArgument , NULL, 0, eArgTypeAddressOrExpression, "Disassemble function containing this address."},
-{ 0 , false, NULL , 0, 0 , NULL, 0, eArgTypeNone, NULL }
+ LLDB_OPT_SET_5 , false, "count" , 'c', OptionParser::eRequiredArgument , NULL, NULL, 0, eArgTypeNumLines, "Number of instructions to display."},
+{ LLDB_OPT_SET_3 , false, "name" , 'n', OptionParser::eRequiredArgument , NULL, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
+ "Disassemble entire contents of the given function name."},
+{ LLDB_OPT_SET_4 , false, "frame" , 'f', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Disassemble from the start of the current frame's function."},
+{ LLDB_OPT_SET_5 , false, "pc" , 'p', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Disassemble around the current pc."},
+{ LLDB_OPT_SET_6 , false, "line" , 'l', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Disassemble the current frame's current source line instructions if there is debug line table information, else disassemble around the pc."},
+{ LLDB_OPT_SET_7 , false, "address" , 'a', OptionParser::eRequiredArgument , NULL, NULL, 0, eArgTypeAddressOrExpression, "Disassemble function containing this address."},
+{ 0 , false, NULL , 0, 0 , NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -370,6 +370,7 @@ CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result)
}
else
{
+ std::vector<AddressRange> ranges;
AddressRange range;
StackFrame *frame = m_exe_ctx.GetFramePtr();
if (m_options.frame_line)
@@ -425,6 +426,7 @@ CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result)
// Disassembling at the PC always disassembles some number of instructions (not the whole function).
m_options.num_instructions = DEFAULT_DISASM_NUM_INS;
}
+ ranges.push_back(range);
}
else
{
@@ -441,49 +443,75 @@ CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result)
}
range.SetByteSize (m_options.end_addr - m_options.start_addr);
}
+ ranges.push_back(range);
}
else
{
if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS
- && target
- && !target->GetSectionLoadList().IsEmpty())
+ && target)
{
- bool failed = false;
- Address symbol_containing_address;
- if (target->GetSectionLoadList().ResolveLoadAddress (m_options.symbol_containing_addr, symbol_containing_address))
+ if (!target->GetSectionLoadList().IsEmpty())
{
- ModuleSP module_sp (symbol_containing_address.GetModule());
- SymbolContext sc;
- bool resolve_tail_call_address = true; // PC can be one past the address range of the function.
- module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc,
- resolve_tail_call_address);
- if (sc.function || sc.symbol)
+ bool failed = false;
+ Address symbol_containing_address;
+ if (target->GetSectionLoadList().ResolveLoadAddress (m_options.symbol_containing_addr, symbol_containing_address))
{
- sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range);
+ ModuleSP module_sp (symbol_containing_address.GetModule());
+ SymbolContext sc;
+ bool resolve_tail_call_address = true; // PC can be one past the address range of the function.
+ module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc,
+ resolve_tail_call_address);
+ if (sc.function || sc.symbol)
+ {
+ sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range);
+ }
+ else
+ {
+ failed = true;
+ }
}
else
{
failed = true;
}
+ if (failed)
+ {
+ result.AppendErrorWithFormat ("Could not find function bounds for address 0x%" PRIx64 "\n", m_options.symbol_containing_addr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ ranges.push_back(range);
}
else
{
- failed = true;
- }
- if (failed)
- {
- result.AppendErrorWithFormat ("Could not find function bounds for address 0x%" PRIx64 "\n", m_options.symbol_containing_addr);
- result.SetStatus (eReturnStatusFailed);
- return false;
+ for (lldb::ModuleSP module_sp : target->GetImages().Modules())
+ {
+ lldb::addr_t file_addr = m_options.symbol_containing_addr;
+ Address file_address;
+ if (module_sp->ResolveFileAddress(file_addr, file_address))
+ {
+ SymbolContext sc;
+ bool resolve_tail_call_address = true; // PC can be one past the address range of the function.
+ module_sp->ResolveSymbolContextForAddress (file_address, eSymbolContextEverything, sc, resolve_tail_call_address);
+ if (sc.function || sc.symbol)
+ {
+ sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range);
+ ranges.push_back(range);
+ }
+ }
+ }
+
}
}
}
}
}
+ else
+ ranges.push_back(range);
if (m_options.num_instructions != 0)
{
- if (!range.GetBaseAddress().IsValid())
+ if (ranges.size() == 0)
{
// The default action is to disassemble the current frame function.
if (frame)
@@ -504,29 +532,38 @@ CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result)
return false;
}
}
-
- if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
- m_options.arch,
- plugin_name,
- flavor_string,
- m_exe_ctx,
- range.GetBaseAddress(),
- m_options.num_instructions,
- m_options.show_mixed ? m_options.num_lines_context : 0,
- options,
- result.GetOutputStream()))
- {
- result.SetStatus (eReturnStatusSuccessFinishResult);
- }
- else
+
+ bool print_sc_header = ranges.size() > 1;
+ for (AddressRange cur_range : ranges)
{
- result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
- result.SetStatus (eReturnStatusFailed);
+ if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
+ m_options.arch,
+ plugin_name,
+ flavor_string,
+ m_exe_ctx,
+ cur_range.GetBaseAddress(),
+ m_options.num_instructions,
+ m_options.show_mixed ? m_options.num_lines_context : 0,
+ options,
+ result.GetOutputStream()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ if (m_options.start_addr != LLDB_INVALID_ADDRESS)
+ result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
+ else if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS)
+ result.AppendErrorWithFormat ("Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n", m_options.symbol_containing_addr);
+ result.SetStatus (eReturnStatusFailed);
+ }
}
+ if (print_sc_header)
+ result.AppendMessage("\n");
}
else
{
- if (!range.GetBaseAddress().IsValid())
+ if (ranges.size() == 0)
{
// The default action is to disassemble the current frame function.
if (frame)
@@ -548,27 +585,35 @@ CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result)
result.SetStatus (eReturnStatusFailed);
return false;
}
+ ranges.push_back(range);
}
- if (range.GetByteSize() == 0)
- range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
-
- if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
- m_options.arch,
- plugin_name,
- flavor_string,
- m_exe_ctx,
- range,
- m_options.num_instructions,
- m_options.show_mixed ? m_options.num_lines_context : 0,
- options,
- result.GetOutputStream()))
+
+ bool print_sc_header = ranges.size() > 1;
+ for (AddressRange cur_range : ranges)
{
- result.SetStatus (eReturnStatusSuccessFinishResult);
- }
- else
- {
- result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
- result.SetStatus (eReturnStatusFailed);
+ if (cur_range.GetByteSize() == 0)
+ cur_range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
+
+ if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
+ m_options.arch,
+ plugin_name,
+ flavor_string,
+ m_exe_ctx,
+ cur_range,
+ m_options.num_instructions,
+ m_options.show_mixed ? m_options.num_lines_context : 0,
+ options,
+ result.GetOutputStream()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ if (print_sc_header)
+ result.AppendMessage("\n");
}
}
}
diff --git a/source/Commands/CommandObjectExpression.cpp b/source/Commands/CommandObjectExpression.cpp
index c772a2e58912..079c62ddfdff 100644
--- a/source/Commands/CommandObjectExpression.cpp
+++ b/source/Commands/CommandObjectExpression.cpp
@@ -34,6 +34,7 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
using namespace lldb;
@@ -59,19 +60,19 @@ static OptionEnumValueElement g_description_verbosity_type[] =
OptionDefinition
CommandObjectExpression::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Should we run all threads if the execution doesn't complete on one thread."},
- { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "ignore-breakpoints", 'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Ignore breakpoint hits while running expressions"},
- { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger, "Timeout value (in microseconds) for running the expression."},
- { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error", 'u', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, or raises a signal. Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."},
- { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "debug", 'g', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "When specified, debug the JIT code by setting a breakpoint on the first instruction and forcing breakpoints to not be ignored (-i0) and no unwinding to happen on error (-u0)."},
- { LLDB_OPT_SET_1, false, "description-verbosity", 'v', OptionParser::eOptionalArgument, g_description_verbosity_type, 0, eArgTypeDescriptionVerbosity, "How verbose should the output of this expression be, if the object description is asked for."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "Should we run all threads if the execution doesn't complete on one thread."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "ignore-breakpoints", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "Ignore breakpoint hits while running expressions"},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger, "Timeout value (in microseconds) for running the expression."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error", 'u', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, or raises a signal. Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "debug", 'g', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "When specified, debug the JIT code by setting a breakpoint on the first instruction and forcing breakpoints to not be ignored (-i0) and no unwinding to happen on error (-u0)."},
+ { LLDB_OPT_SET_1, false, "description-verbosity", 'v', OptionParser::eOptionalArgument, NULL, g_description_verbosity_type, 0, eArgTypeDescriptionVerbosity, "How verbose should the output of this expression be, if the object description is asked for."},
};
uint32_t
CommandObjectExpression::CommandOptions::GetNumDefinitions ()
{
- return sizeof(g_option_table)/sizeof(OptionDefinition);
+ return llvm::array_lengthof(g_option_table);
}
Error
@@ -173,7 +174,7 @@ CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpret
}
else
{
- ignore_breakpoints = false;
+ ignore_breakpoints = true;
unwind_on_error = true;
}
@@ -205,7 +206,7 @@ CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interprete
{
SetHelpLong(
"Timeouts:\n\
- If the expression can be evaluated statically (without runnning code) then it will be.\n\
+ If the expression can be evaluated statically (without running code) then it will be.\n\
Otherwise, by default the expression will run on the current thread with a short timeout:\n\
currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted\n\
and resumed with all threads running. You can use the -a option to disable retrying on all\n\
@@ -217,6 +218,15 @@ User defined variables:\n\
your user defined variable is a $, then the variable's value will be available in future\n\
expressions, otherwise it will just be available in the current expression.\n\
\n\
+\n\
+Continuing evaluation after a breakpoint:\n\
+ If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once\n\
+ you are done with your investigation, you can either remove the expression execution frames\n\
+ from the stack with \"thread return -x\" or if you are still interested in the expression result\n\
+ you can issue the \"continue\" command and the expression evaluation will complete and the\n\
+ expression result will be available using the \"thread.completed-expression\" key in the thread\n\
+ format.\n\
+\n\
Examples: \n\
\n\
expr my_struct->a = my_array[3] \n\
@@ -277,8 +287,6 @@ CommandObjectExpression::EvaluateExpression
{
lldb::ValueObjectSP result_valobj_sp;
- ExecutionResults exe_results;
-
bool keep_in_memory = true;
EvaluateExpressionOptions options;
@@ -290,15 +298,19 @@ CommandObjectExpression::EvaluateExpression
options.SetTryAllThreads(m_command_options.try_all_threads);
options.SetDebug(m_command_options.debug);
+ // If there is any chance we are going to stop and want to see
+ // what went wrong with our expression, we should generate debug info
+ if (!m_command_options.ignore_breakpoints ||
+ !m_command_options.unwind_on_error)
+ options.SetGenerateDebugInfo(true);
+
if (m_command_options.timeout > 0)
options.SetTimeoutUsec(m_command_options.timeout);
else
options.SetTimeoutUsec(0);
-
- exe_results = target->EvaluateExpression (expr,
- exe_ctx.GetFramePtr(),
- result_valobj_sp,
- options);
+
+ target->EvaluateExpression(expr, exe_ctx.GetFramePtr(),
+ result_valobj_sp, options);
if (result_valobj_sp)
{
@@ -406,6 +418,30 @@ CommandObjectExpression::IOHandlerLinesUpdated (IOHandler &io_handler,
return LineStatus::Success;
}
+void
+CommandObjectExpression::GetMultilineExpression ()
+{
+ m_expr_lines.clear();
+ m_expr_line_count = 0;
+
+ Debugger &debugger = GetCommandInterpreter().GetDebugger();
+ const bool multiple_lines = true; // Get multiple lines
+ IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
+ "lldb-expr", // Name of input reader for history
+ NULL, // No prompt
+ multiple_lines,
+ 1, // Show line numbers starting at 1
+ *this));
+
+ StreamFileSP output_sp(io_handler_sp->GetOutputStreamFile());
+ if (output_sp)
+ {
+ output_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
+ output_sp->Flush();
+ }
+ debugger.PushIOHandler(io_handler_sp);
+}
+
bool
CommandObjectExpression::DoExecute
(
@@ -419,24 +455,7 @@ CommandObjectExpression::DoExecute
if (command[0] == '\0')
{
- m_expr_lines.clear();
- m_expr_line_count = 0;
-
- Debugger &debugger = GetCommandInterpreter().GetDebugger();
- const bool multiple_lines = true; // Get multiple lines
- IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
- "lldb-expr", // Name of input reader for history
- NULL, // No prompt
- multiple_lines,
- *this));
-
- StreamFileSP output_sp(io_handler_sp->GetOutputStreamFile());
- if (output_sp)
- {
- output_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
- output_sp->Flush();
- }
- debugger.PushIOHandler(io_handler_sp);
+ GetMultilineExpression ();
return result.Succeeded();
}
@@ -475,6 +494,13 @@ CommandObjectExpression::DoExecute
result.SetStatus (eReturnStatusFailed);
return false;
}
+
+ // No expression following options
+ if (expr == NULL || expr[0] == '\0')
+ {
+ GetMultilineExpression ();
+ return result.Succeeded();
+ }
}
}
diff --git a/source/Commands/CommandObjectExpression.h b/source/Commands/CommandObjectExpression.h
index c943f0e8023d..168140d7fe56 100644
--- a/source/Commands/CommandObjectExpression.h
+++ b/source/Commands/CommandObjectExpression.h
@@ -96,6 +96,9 @@ protected:
Stream *output_stream,
Stream *error_stream,
CommandReturnObject *result = NULL);
+
+ void
+ GetMultilineExpression ();
OptionGroupOptions m_option_group;
OptionGroupFormat m_format_options;
diff --git a/source/Commands/CommandObjectFrame.cpp b/source/Commands/CommandObjectFrame.cpp
index 0ef973261508..ce540a5c3100 100644
--- a/source/Commands/CommandObjectFrame.cpp
+++ b/source/Commands/CommandObjectFrame.cpp
@@ -204,7 +204,7 @@ protected:
if (m_options.relative_frame_offset < 0)
{
- if (frame_idx >= -m_options.relative_frame_offset)
+ if (static_cast<int32_t>(frame_idx) >= -m_options.relative_frame_offset)
frame_idx += m_options.relative_frame_offset;
else
{
@@ -224,7 +224,7 @@ protected:
// I don't want "up 20" where "20" takes you past the top of the stack to produce
// an error, but rather to just go to the top. So I have to count the stack here...
const uint32_t num_frames = thread->GetStackFrameCount();
- if (num_frames - frame_idx > m_options.relative_frame_offset)
+ if (static_cast<int32_t>(num_frames - frame_idx) > m_options.relative_frame_offset)
frame_idx += m_options.relative_frame_offset;
else
{
@@ -291,8 +291,8 @@ protected:
OptionDefinition
CommandObjectFrameSelect::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_1, false, "relative", 'r', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOffset, "A relative frame index offset from the current frame index."},
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_1, false, "relative", 'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOffset, "A relative frame index offset from the current frame index."},
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#pragma mark CommandObjectFrameVariable
@@ -471,7 +471,7 @@ protected:
if (regex.GetErrorAsCString(regex_error, sizeof(regex_error)))
result.GetErrorStream().Printf ("error: %s\n", regex_error);
else
- result.GetErrorStream().Printf ("error: unkown regex error when compiling '%s'\n", name_cstr);
+ result.GetErrorStream().Printf ("error: unknown regex error when compiling '%s'\n", name_cstr);
}
}
else // No regex, either exact variable names or variable expressions.
diff --git a/source/Commands/CommandObjectHelp.cpp b/source/Commands/CommandObjectHelp.cpp
index bd0c3938c702..f73d9d23b574 100644
--- a/source/Commands/CommandObjectHelp.cpp
+++ b/source/Commands/CommandObjectHelp.cpp
@@ -54,9 +54,9 @@ CommandObjectHelp::~CommandObjectHelp()
OptionDefinition
CommandObjectHelp::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "show-aliases", 'a', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Show aliases in the command list."},
- { LLDB_OPT_SET_ALL, false, "hide-user-commands", 'u', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Hide user-defined commands from the list."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "show-aliases", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Show aliases in the command list."},
+ { LLDB_OPT_SET_ALL, false, "hide-user-commands", 'u', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Hide user-defined commands from the list."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
bool
diff --git a/source/Commands/CommandObjectLog.cpp b/source/Commands/CommandObjectLog.cpp
index 2d815846a607..7d32cc6d08a5 100644
--- a/source/Commands/CommandObjectLog.cpp
+++ b/source/Commands/CommandObjectLog.cpp
@@ -215,16 +215,16 @@ protected:
OptionDefinition
CommandObjectLogEnable::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename, "Set the destination file to log to."},
-{ LLDB_OPT_SET_1, false, "threadsafe", 't', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Enable thread safe logging to avoid interweaved log lines." },
-{ LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Enable verbose logging." },
-{ LLDB_OPT_SET_1, false, "debug", 'g', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Enable debug logging." },
-{ LLDB_OPT_SET_1, false, "sequence", 's', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Prepend all log lines with an increasing integer sequence id." },
-{ LLDB_OPT_SET_1, false, "timestamp", 'T', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Prepend all log lines with a timestamp." },
-{ LLDB_OPT_SET_1, false, "pid-tid", 'p', OptionParser::eNoArgument, 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, 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, 0, eArgTypeNone, "Append a stack backtrace to each log line." },
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, "Set the destination file to log to."},
+{ LLDB_OPT_SET_1, false, "threadsafe", 't', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Enable thread safe logging to avoid interweaved log lines." },
+{ LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Enable verbose logging." },
+{ LLDB_OPT_SET_1, false, "debug", 'g', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Enable debug logging." },
+{ LLDB_OPT_SET_1, false, "sequence", 's', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Prepend all log lines with an increasing integer sequence id." },
+{ LLDB_OPT_SET_1, false, "timestamp", 'T', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Prepend all log lines with a timestamp." },
+{ 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." },
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
class CommandObjectLogDisable : public CommandObjectParsed
diff --git a/source/Commands/CommandObjectMemory.cpp b/source/Commands/CommandObjectMemory.cpp
index cb7398fb9554..bfbb296158a9 100644
--- a/source/Commands/CommandObjectMemory.cpp
+++ b/source/Commands/CommandObjectMemory.cpp
@@ -42,12 +42,12 @@ using namespace lldb_private;
static OptionDefinition
g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "num-per-line" ,'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNumberPerLine ,"The number of items per line to display."},
- { LLDB_OPT_SET_2, false, "binary" ,'b', OptionParser::eNoArgument , NULL, 0, eArgTypeNone ,"If true, memory will be saved as binary. If false, the memory is saved save as an ASCII dump that uses the format, size, count and number per line settings."},
- { LLDB_OPT_SET_3, true , "type" ,'t', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNone ,"The name of a type to view memory as."},
+ { LLDB_OPT_SET_1, false, "num-per-line" ,'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeNumberPerLine ,"The number of items per line to display."},
+ { LLDB_OPT_SET_2, false, "binary" ,'b', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone ,"If true, memory will be saved as binary. If false, the memory is saved save as an ASCII dump that uses the format, size, count and number per line settings."},
+ { LLDB_OPT_SET_3, true , "type" ,'t', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeNone ,"The name of a type to view memory as."},
{ LLDB_OPT_SET_1|
LLDB_OPT_SET_2|
- LLDB_OPT_SET_3, false, "force" ,'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone ,"Necessary if reading over target.max-memory-read-size bytes."},
+ LLDB_OPT_SET_3, false, "force" ,'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone ,"Necessary if reading over target.max-memory-read-size bytes."},
};
@@ -651,7 +651,7 @@ protected:
}
else if (m_format_options.GetCountValue().OptionWasSet())
{
- result.AppendErrorWithFormat("specify either the end address (0x%" PRIx64 ") or the count (--count %zu), not both.\n", end_addr, item_count);
+ result.AppendErrorWithFormat("specify either the end address (0x%" PRIx64 ") or the count (--count %" PRIu64 "), not both.\n", end_addr, (uint64_t)item_count);
result.SetStatus(eReturnStatusFailed);
return false;
}
@@ -685,7 +685,7 @@ protected:
data_sp.reset (new DataBufferHeap (total_byte_size, '\0'));
if (data_sp->GetBytes() == NULL)
{
- result.AppendErrorWithFormat ("can't allocate 0x%zx bytes for the memory read buffer, specify a smaller size to read", total_byte_size);
+ result.AppendErrorWithFormat ("can't allocate 0x%" PRIx32 " bytes for the memory read buffer, specify a smaller size to read", (uint32_t)total_byte_size);
result.SetStatus(eReturnStatusFailed);
return false;
}
@@ -708,7 +708,7 @@ protected:
}
if (bytes_read < total_byte_size)
- result.AppendWarningWithFormat("Not all bytes (%zu/%zu) were able to be read from 0x%" PRIx64 ".\n", bytes_read, total_byte_size, addr);
+ result.AppendWarningWithFormat("Not all bytes (%" PRIu64 "/%" PRIu64 ") were able to be read from 0x%" PRIx64 ".\n", (uint64_t)bytes_read, (uint64_t)total_byte_size, addr);
}
else
{
@@ -878,7 +878,7 @@ protected:
// here we passed a count, and it was not 1
// so we have a byte_size and a count
// we could well multiply those, but instead let's just fail
- result.AppendErrorWithFormat("reading memory as characters of size %zu is not supported", item_byte_size);
+ result.AppendErrorWithFormat("reading memory as characters of size %" PRIu64 " is not supported", (uint64_t)item_byte_size);
result.SetStatus(eReturnStatusFailed);
return false;
}
@@ -917,10 +917,10 @@ protected:
OptionDefinition
g_memory_find_option_table[] =
{
- { LLDB_OPT_SET_1, false, "expression", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeExpression, "Evaluate an expression to obtain a byte pattern."},
- { LLDB_OPT_SET_2, false, "string", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Use text to find a byte pattern."},
- { LLDB_OPT_SET_1|LLDB_OPT_SET_2, false, "count", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount, "How many times to perform the search."},
- { LLDB_OPT_SET_1|LLDB_OPT_SET_2, false, "dump-offset", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOffset, "When dumping memory for a match, an offset from the match location to start dumping from."},
+ { LLDB_OPT_SET_1, false, "expression", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeExpression, "Evaluate an expression to obtain a byte pattern."},
+ { LLDB_OPT_SET_2, false, "string", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Use text to find a byte pattern."},
+ { LLDB_OPT_SET_1|LLDB_OPT_SET_2, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCount, "How many times to perform the search."},
+ { LLDB_OPT_SET_1|LLDB_OPT_SET_2, false, "dump-offset", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOffset, "When dumping memory for a match, an offset from the match location to start dumping from."},
};
//----------------------------------------------------------------------
@@ -1223,8 +1223,8 @@ protected:
OptionDefinition
g_memory_write_option_table[] =
{
-{ LLDB_OPT_SET_1, true, "infile", 'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
-{ LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOffset, "Start writng bytes from an offset within the input file."},
+{ LLDB_OPT_SET_1, true, "infile", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
+{ LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOffset, "Start writing bytes from an offset within the input file."},
};
//----------------------------------------------------------------------
@@ -1536,7 +1536,7 @@ protected:
}
else if (!UIntValueIsValidForSize (uval64, item_byte_size))
{
- result.AppendErrorWithFormat ("Value 0x%" PRIx64 " is too large to fit in a %zu byte unsigned integer value.\n", uval64, item_byte_size);
+ result.AppendErrorWithFormat("Value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size);
result.SetStatus(eReturnStatusFailed);
return false;
}
@@ -1564,7 +1564,7 @@ protected:
}
else if (!UIntValueIsValidForSize (uval64, item_byte_size))
{
- result.AppendErrorWithFormat ("Value 0x%" PRIx64 " is too large to fit in a %zu byte unsigned integer value.\n", uval64, item_byte_size);
+ result.AppendErrorWithFormat("Value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size);
result.SetStatus(eReturnStatusFailed);
return false;
}
@@ -1604,7 +1604,7 @@ protected:
}
else if (!SIntValueIsValidForSize (sval64, item_byte_size))
{
- result.AppendErrorWithFormat ("Value %" PRIi64 " is too large or small to fit in a %zu byte signed integer value.\n", sval64, item_byte_size);
+ result.AppendErrorWithFormat ("Value %" PRIi64 " is too large or small to fit in a %" PRIu64 " byte signed integer value.\n", sval64, (uint64_t)item_byte_size);
result.SetStatus(eReturnStatusFailed);
return false;
}
@@ -1621,7 +1621,7 @@ protected:
}
else if (!UIntValueIsValidForSize (uval64, item_byte_size))
{
- result.AppendErrorWithFormat ("Value %" PRIu64 " is too large to fit in a %zu byte unsigned integer value.\n", uval64, item_byte_size);
+ result.AppendErrorWithFormat ("Value %" PRIu64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size);
result.SetStatus(eReturnStatusFailed);
return false;
}
@@ -1638,7 +1638,7 @@ protected:
}
else if (!UIntValueIsValidForSize (uval64, item_byte_size))
{
- result.AppendErrorWithFormat ("Value %" PRIo64 " is too large to fit in a %zu byte unsigned integer value.\n", uval64, item_byte_size);
+ result.AppendErrorWithFormat ("Value %" PRIo64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size);
result.SetStatus(eReturnStatusFailed);
return false;
}
diff --git a/source/Commands/CommandObjectPlatform.cpp b/source/Commands/CommandObjectPlatform.cpp
index 5e842bf848a3..9998dbdccdad 100644
--- a/source/Commands/CommandObjectPlatform.cpp
+++ b/source/Commands/CommandObjectPlatform.cpp
@@ -21,6 +21,7 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandOptionValidators.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionGroupFile.h"
#include "lldb/Interpreter/OptionGroupPlatform.h"
@@ -64,20 +65,19 @@ ParsePermissionString(const char* permissions)
static OptionDefinition
g_permissions_options[] =
{
- { LLDB_OPT_SET_ALL, false, "permissions-value", 'v', OptionParser::eRequiredArgument, NULL, 0, eArgTypePermissionsNumber , "Give out the numeric value for permissions (e.g. 757)" },
- { LLDB_OPT_SET_ALL, false, "permissions-string",'s', OptionParser::eRequiredArgument, NULL, 0, eArgTypePermissionsString , "Give out the string value for permissions (e.g. rwxr-xr--)." },
- { LLDB_OPT_SET_ALL, false, "user-read", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Allow user to read." },
- { LLDB_OPT_SET_ALL, false, "user-write", 'w', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Allow user to write." },
- { LLDB_OPT_SET_ALL, false, "user-exec", 'x', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Allow user to execute." },
-
- { LLDB_OPT_SET_ALL, false, "group-read", 'R', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Allow group to read." },
- { LLDB_OPT_SET_ALL, false, "group-write", 'W', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Allow group to write." },
- { LLDB_OPT_SET_ALL, false, "group-exec", 'X', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Allow group to execute." },
-
- { LLDB_OPT_SET_ALL, false, "world-read", 'd', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Allow world to read." },
- { LLDB_OPT_SET_ALL, false, "world-write", 't', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Allow world to write." },
- { LLDB_OPT_SET_ALL, false, "world-exec", 'e', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Allow world to execute." },
-
+ { LLDB_OPT_SET_ALL, false, "permissions-value", 'v', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePermissionsNumber , "Give out the numeric value for permissions (e.g. 757)" },
+ { LLDB_OPT_SET_ALL, false, "permissions-string", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePermissionsString , "Give out the string value for permissions (e.g. rwxr-xr--)." },
+ { LLDB_OPT_SET_ALL, false, "user-read", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow user to read." },
+ { LLDB_OPT_SET_ALL, false, "user-write", 'w', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow user to write." },
+ { LLDB_OPT_SET_ALL, false, "user-exec", 'x', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow user to execute." },
+
+ { LLDB_OPT_SET_ALL, false, "group-read", 'R', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow group to read." },
+ { LLDB_OPT_SET_ALL, false, "group-write", 'W', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow group to write." },
+ { LLDB_OPT_SET_ALL, false, "group-exec", 'X', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow group to execute." },
+
+ { LLDB_OPT_SET_ALL, false, "world-read", 'd', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow world to read." },
+ { LLDB_OPT_SET_ALL, false, "world-write", 't', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow world to write." },
+ { LLDB_OPT_SET_ALL, false, "world-exec", 'e', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow world to execute." },
};
class OptionPermissions : public lldb_private::OptionGroup
@@ -894,9 +894,9 @@ protected:
OptionDefinition
CommandObjectPlatformFRead::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "offset" , 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeIndex , "Offset into the file at which to start reading." },
- { LLDB_OPT_SET_1, false, "count" , 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount , "Number of bytes to read from the file." },
- { 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone , NULL }
+ { LLDB_OPT_SET_1, false, "offset" , 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeIndex , "Offset into the file at which to start reading." },
+ { LLDB_OPT_SET_1, false, "count" , 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCount , "Number of bytes to read from the file." },
+ { 0 , false, NULL , 0 , 0 , NULL, NULL, 0, eArgTypeNone , NULL }
};
@@ -1020,9 +1020,9 @@ protected:
OptionDefinition
CommandObjectPlatformFWrite::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "offset" , 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeIndex , "Offset into the file at which to start reading." },
- { LLDB_OPT_SET_1, false, "data" , 'd', OptionParser::eRequiredArgument, NULL, 0, eArgTypeValue , "Text to write to the file." },
- { 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone , NULL }
+ { LLDB_OPT_SET_1, false, "offset" , 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeIndex , "Offset into the file at which to start reading." },
+ { LLDB_OPT_SET_1, false, "data" , 'd', OptionParser::eRequiredArgument , NULL, NULL, 0, eArgTypeValue , "Text to write to the file." },
+ { 0 , false, NULL , 0 , 0 , NULL, NULL, 0, eArgTypeNone , NULL }
};
class CommandObjectPlatformFile : public CommandObjectMultiword
@@ -1645,24 +1645,29 @@ protected:
CommandOptions m_options;
};
+namespace
+{
+ PosixPlatformCommandOptionValidator g_posix_validator;
+}
+
OptionDefinition
CommandObjectPlatformProcessList::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_1 , false, "pid" , 'p', OptionParser::eRequiredArgument, NULL, 0, eArgTypePid , "List the process info for a specific process ID." },
-{ LLDB_OPT_SET_2 , true , "name" , 'n', OptionParser::eRequiredArgument, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that match a string." },
-{ LLDB_OPT_SET_3 , true , "ends-with" , 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that end with a string." },
-{ LLDB_OPT_SET_4 , true , "starts-with", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that start with a string." },
-{ LLDB_OPT_SET_5 , true , "contains" , 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that contain a string." },
-{ LLDB_OPT_SET_6 , true , "regex" , 'r', OptionParser::eRequiredArgument, NULL, 0, eArgTypeRegularExpression, "Find processes with executable basenames that match a regular expression." },
-{ LLDB_OPT_SET_FROM_TO(2, 6), false, "parent" , 'P', OptionParser::eRequiredArgument, NULL, 0, eArgTypePid , "Find processes that have a matching parent process ID." },
-{ LLDB_OPT_SET_FROM_TO(2, 6), false, "uid" , 'u', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching user ID." },
-{ LLDB_OPT_SET_FROM_TO(2, 6), false, "euid" , 'U', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective user ID." },
-{ LLDB_OPT_SET_FROM_TO(2, 6), false, "gid" , 'g', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching group ID." },
-{ LLDB_OPT_SET_FROM_TO(2, 6), false, "egid" , 'G', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective group ID." },
-{ LLDB_OPT_SET_FROM_TO(2, 6), false, "arch" , 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeArchitecture , "Find processes that have a matching architecture." },
-{ LLDB_OPT_SET_FROM_TO(1, 6), false, "show-args" , 'A', OptionParser::eNoArgument , NULL, 0, eArgTypeNone , "Show process arguments instead of the process executable basename." },
-{ LLDB_OPT_SET_FROM_TO(1, 6), false, "verbose" , 'v', OptionParser::eNoArgument , NULL, 0, eArgTypeNone , "Enable verbose output." },
-{ 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone , NULL }
+{ LLDB_OPT_SET_1 , false, "pid" , 'p', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePid , "List the process info for a specific process ID." },
+{ LLDB_OPT_SET_2 , true , "name" , 'n', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that match a string." },
+{ LLDB_OPT_SET_3 , true , "ends-with" , 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that end with a string." },
+{ LLDB_OPT_SET_4 , true , "starts-with", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that start with a string." },
+{ LLDB_OPT_SET_5 , true , "contains" , 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that contain a string." },
+{ LLDB_OPT_SET_6 , true , "regex" , 'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "Find processes with executable basenames that match a regular expression." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "parent" , 'P', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePid , "Find processes that have a matching parent process ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "uid" , 'u', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching user ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "euid" , 'U', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective user ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "gid" , 'g', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching group ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "egid" , 'G', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective group ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "arch" , 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeArchitecture , "Find processes that have a matching architecture." },
+{ LLDB_OPT_SET_FROM_TO(1, 6), false, "show-args" , 'A', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone , "Show process arguments instead of the process executable basename." },
+{ LLDB_OPT_SET_FROM_TO(1, 6), false, "verbose" , 'v', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone , "Enable verbose output." },
+{ 0 , false, NULL , 0 , 0 , NULL, NULL, 0, eArgTypeNone , NULL }
};
//----------------------------------------------------------------------
@@ -1965,11 +1970,11 @@ protected:
OptionDefinition
CommandObjectPlatformProcessAttach::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "plugin", 'P', OptionParser::eRequiredArgument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
- { LLDB_OPT_SET_1, false, "pid", 'p', OptionParser::eRequiredArgument, NULL, 0, eArgTypePid, "The process ID of an existing process to attach to."},
- { LLDB_OPT_SET_2, false, "name", 'n', OptionParser::eRequiredArgument, NULL, 0, eArgTypeProcessName, "The name of the process to attach to."},
- { LLDB_OPT_SET_2, false, "waitfor",'w', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Wait for the the process with <process-name> to launch."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { 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."},
+ { 0, false, NULL , 0 , 0 , NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -2192,8 +2197,8 @@ public:
OptionDefinition
CommandObjectPlatformShell::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "timeout", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeValue, "Seconds to wait for the remote host to finish running the command."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "timeout", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeValue, "Seconds to wait for the remote host to finish running the command."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp
index 49a392286c6a..6536c6ef1693 100644
--- a/source/Commands/CommandObjectProcess.cpp
+++ b/source/Commands/CommandObjectProcess.cpp
@@ -20,6 +20,7 @@
#include "lldb/Breakpoint/BreakpointSite.h"
#include "lldb/Core/State.h"
#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/Options.h"
@@ -204,8 +205,28 @@ protected:
const char *target_settings_argv0 = target->GetArg0();
- if (target->GetDisableASLR())
+ // Determine whether we will disable ASLR or leave it in the default state (i.e. enabled if the platform supports it).
+ // First check if the process launch options explicitly turn on/off disabling ASLR. If so, use that setting;
+ // otherwise, use the 'settings target.disable-aslr' setting.
+ bool disable_aslr = false;
+ if (m_options.disable_aslr != eLazyBoolCalculate)
+ {
+ // The user specified an explicit setting on the process launch line. Use it.
+ disable_aslr = (m_options.disable_aslr == eLazyBoolYes);
+ }
+ else
+ {
+ // The user did not explicitly specify whether to disable ASLR. Fall back to the target.disable-aslr setting.
+ disable_aslr = target->GetDisableASLR ();
+ }
+
+ if (disable_aslr)
m_options.launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+ else
+ m_options.launch_info.GetFlags().Clear (eLaunchFlagDisableASLR);
+
+ if (target->GetDetachOnError())
+ m_options.launch_info.GetFlags().Set (eLaunchFlagDetachOnError);
if (target->GetDisableSTDIO())
m_options.launch_info.GetFlags().Set (eLaunchFlagDisableSTDIO);
@@ -532,6 +553,9 @@ protected:
if (error.Success())
{
+ // Update the execution context so the current target and process are now selected
+ // in case we interrupt
+ m_interpreter.UpdateExecutionContext(NULL);
ListenerSP listener_sp (new Listener("lldb.CommandObjectProcessAttach.DoExecute.attach.hijack"));
m_options.attach_info.SetHijackListener(listener_sp);
process->HijackProcessEvents(listener_sp.get());
@@ -553,7 +577,11 @@ protected:
}
else
{
- result.AppendError ("attach failed: process did not stop (no such process or permission problem?)");
+ 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.SetStatus (eReturnStatusFailed);
}
@@ -617,13 +645,13 @@ protected:
OptionDefinition
CommandObjectProcessAttach::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_ALL, false, "continue",'c', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Immediately continue the process once attached."},
-{ LLDB_OPT_SET_ALL, false, "plugin", 'P', OptionParser::eRequiredArgument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
-{ LLDB_OPT_SET_1, false, "pid", 'p', OptionParser::eRequiredArgument, NULL, 0, eArgTypePid, "The process ID of an existing process to attach to."},
-{ LLDB_OPT_SET_2, false, "name", 'n', OptionParser::eRequiredArgument, NULL, 0, eArgTypeProcessName, "The name of the process to attach to."},
-{ LLDB_OPT_SET_2, false, "include-existing", 'i', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Include existing processes when doing attach -w."},
-{ LLDB_OPT_SET_2, false, "waitfor", 'w', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Wait for the process with <process-name> to launch."},
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_ALL, false, "continue",'c', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Immediately continue the process once attached."},
+{ 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, "include-existing", 'i', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Include existing processes when doing attach -w."},
+{ 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 }
};
//-------------------------------------------------------------------------
@@ -758,13 +786,20 @@ protected:
// Set the actions that the threads should each take when resuming
for (uint32_t idx=0; idx<num_threads; ++idx)
{
- process->GetThreadList().GetThreadAtIndex(idx)->SetResumeState (eStateRunning);
+ const bool override_suspend = false;
+ process->GetThreadList().GetThreadAtIndex(idx)->SetResumeState (eStateRunning, override_suspend);
}
}
-
+
Error error(process->Resume());
+
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);
+
result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
if (synchronous_execution)
{
@@ -807,9 +842,9 @@ protected:
OptionDefinition
CommandObjectProcessContinue::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_ALL, false, "ignore-count",'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger,
+{ LLDB_OPT_SET_ALL, false, "ignore-count",'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger,
"Ignore <N> crossings of the breakpoint (if it exists) for the currently selected thread."},
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -911,7 +946,6 @@ protected:
DoExecute (Args& command, CommandReturnObject &result)
{
Process *process = m_exe_ctx.GetProcessPtr();
- result.AppendMessageWithFormat ("Detaching from process %" PRIu64 "\n", process->GetID());
// FIXME: This will be a Command Option:
bool keep_stopped;
if (m_options.m_keep_stopped == eLazyBoolCalculate)
@@ -947,8 +981,8 @@ protected:
OptionDefinition
CommandObjectProcessDetach::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_1, false, "keep-stopped", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Whether or not the process should be kept stopped on detach (if possible)." },
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_1, false, "keep-stopped", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "Whether or not the process should be kept stopped on detach (if possible)." },
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -1119,8 +1153,8 @@ protected:
OptionDefinition
CommandObjectProcessConnect::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "plugin", 'p', OptionParser::eRequiredArgument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
- { 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "plugin", 'p', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
+ { 0, false, NULL, 0 , 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -1483,6 +1517,71 @@ protected:
};
//-------------------------------------------------------------------------
+// CommandObjectProcessSaveCore
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessSaveCore
+
+class CommandObjectProcessSaveCore : public CommandObjectParsed
+{
+public:
+
+ CommandObjectProcessSaveCore (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process save-core",
+ "Save the current process as a core file using an appropriate file type.",
+ "process save-core FILE",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched)
+ {
+ }
+
+ ~CommandObjectProcessSaveCore ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ ProcessSP process_sp = m_exe_ctx.GetProcessSP();
+ if (process_sp)
+ {
+ if (command.GetArgumentCount() == 1)
+ {
+ FileSpec output_file(command.GetArgumentAtIndex(0), false);
+ Error error = PluginManager::SaveCore(process_sp, output_file);
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to save core file for process: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' takes one arguments:\nUsage: %s\n",
+ m_cmd_name.c_str(),
+ m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid process");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
// CommandObjectProcessStatus
//-------------------------------------------------------------------------
#pragma mark CommandObjectProcessStatus
@@ -1824,10 +1923,10 @@ protected:
OptionDefinition
CommandObjectProcessHandle::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_1, false, "stop", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Whether or not the process should be stopped if the signal is received." },
-{ LLDB_OPT_SET_1, false, "notify", 'n', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Whether or not the debugger should notify the user if the signal is received." },
-{ LLDB_OPT_SET_1, false, "pass", 'p', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Whether or not the signal should be passed to the process." },
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_1, false, "stop", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "Whether or not the process should be stopped if the signal is received." },
+{ LLDB_OPT_SET_1, false, "notify", 'n', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "Whether or not the debugger should notify the user if the signal is received." },
+{ LLDB_OPT_SET_1, false, "pass", 'p', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "Whether or not the signal should be passed to the process." },
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -1853,6 +1952,7 @@ CommandObjectMultiwordProcess::CommandObjectMultiwordProcess (CommandInterpreter
LoadSubCommand ("interrupt", CommandObjectSP (new CommandObjectProcessInterrupt (interpreter)));
LoadSubCommand ("kill", CommandObjectSP (new CommandObjectProcessKill (interpreter)));
LoadSubCommand ("plugin", CommandObjectSP (new CommandObjectProcessPlugin (interpreter)));
+ LoadSubCommand ("save-core", CommandObjectSP (new CommandObjectProcessSaveCore (interpreter)));
}
CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess ()
diff --git a/source/Commands/CommandObjectQuit.cpp b/source/Commands/CommandObjectQuit.cpp
index ffe2a9240726..dd0efc61b2d0 100644
--- a/source/Commands/CommandObjectQuit.cpp
+++ b/source/Commands/CommandObjectQuit.cpp
@@ -53,7 +53,7 @@ CommandObjectQuit::ShouldAskForConfirmation (bool& is_a_detach)
continue;
const TargetList& target_list(debugger_sp->GetTargetList());
for (uint32_t target_idx = 0;
- target_idx < target_list.GetNumTargets();
+ target_idx < static_cast<uint32_t>(target_list.GetNumTargets());
target_idx++)
{
TargetSP target_sp(target_list.GetTargetAtIndex(target_idx));
diff --git a/source/Commands/CommandObjectRegister.cpp b/source/Commands/CommandObjectRegister.cpp
index deaf2ab3793e..81b79b8cd8b2 100644
--- a/source/Commands/CommandObjectRegister.cpp
+++ b/source/Commands/CommandObjectRegister.cpp
@@ -31,6 +31,7 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Thread.h"
+#include "llvm/ADT/STLExtras.h"
using namespace lldb;
using namespace lldb_private;
@@ -202,7 +203,7 @@ protected:
}
else
{
- result.AppendErrorWithFormat ("invalid register set index: %zu\n", set_idx);
+ result.AppendErrorWithFormat("invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx);
result.SetStatus (eReturnStatusFailed);
break;
}
@@ -352,15 +353,15 @@ protected:
const OptionDefinition
CommandObjectRegisterRead::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "alternate", 'A', OptionParser::eNoArgument , NULL, 0, eArgTypeNone , "Display register names using the alternate register name if there is one."},
- { LLDB_OPT_SET_1 , false, "set" , 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeIndex , "Specify which register sets to dump by index."},
- { LLDB_OPT_SET_2 , false, "all" , 'a', OptionParser::eNoArgument , NULL, 0, eArgTypeNone , "Show all register sets."},
+ { LLDB_OPT_SET_ALL, false, "alternate", 'A', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone , "Display register names using the alternate register name if there is one."},
+ { LLDB_OPT_SET_1 , false, "set" , 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeIndex , "Specify which register sets to dump by index."},
+ { LLDB_OPT_SET_2 , false, "all" , 'a', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone , "Show all register sets."},
};
uint32_t
CommandObjectRegisterRead::CommandOptions::GetNumDefinitions ()
{
- return sizeof(g_option_table)/sizeof(OptionDefinition);
+ return llvm::array_lengthof(g_option_table);
}
diff --git a/source/Commands/CommandObjectSettings.cpp b/source/Commands/CommandObjectSettings.cpp
index 78a5ad6ca86a..ed677afabcb5 100644
--- a/source/Commands/CommandObjectSettings.cpp
+++ b/source/Commands/CommandObjectSettings.cpp
@@ -164,7 +164,8 @@ insert-before or insert-after.\n");
const size_t argc = input.GetArgumentCount();
const char *arg = NULL;
int setting_var_idx;
- for (setting_var_idx = 1; setting_var_idx < argc; ++setting_var_idx)
+ for (setting_var_idx = 1; setting_var_idx < static_cast<int>(argc);
+ ++setting_var_idx)
{
arg = input.GetArgumentAtIndex(setting_var_idx);
if (arg && arg[0] != '-')
@@ -288,8 +289,8 @@ private:
OptionDefinition
CommandObjectSettingsSet::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_2, false, "global", 'g', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Apply the new value to the global default value." },
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_2, false, "global", 'g', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Apply the new value to the global default value." },
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -1154,7 +1155,7 @@ protected:
if (argc != 1)
{
- result.AppendError ("'setttings clear' takes exactly one argument");
+ result.AppendError ("'settings clear' takes exactly one argument");
result.SetStatus (eReturnStatusFailed);
return false;
}
diff --git a/source/Commands/CommandObjectSource.cpp b/source/Commands/CommandObjectSource.cpp
index bf2a42e0bea0..6b1b6aacc857 100644
--- a/source/Commands/CommandObjectSource.cpp
+++ b/source/Commands/CommandObjectSource.cpp
@@ -138,9 +138,9 @@ protected:
OptionDefinition
CommandObjectSourceInfo::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_1, false, "line", 'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeLineNum, "The line number at which to start the display source."},
-{ LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."},
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_1, false, "line", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLineNum, "The line number at which to start the display source."},
+{ LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."},
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#pragma mark CommandObjectSourceList
@@ -804,7 +804,7 @@ protected:
result.SetStatus (eReturnStatusFailed);
return false;
}
-
+
if (num_matches > 1)
{
bool got_multiple = false;
@@ -820,7 +820,7 @@ protected:
{
if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
got_multiple = true;
- break;
+ break;
}
else
test_cu_spec = sc.comp_unit;
@@ -828,7 +828,7 @@ protected:
}
if (got_multiple)
{
- result.AppendErrorWithFormat("Multiple source files found matching: \"%s.\"\n",
+ result.AppendErrorWithFormat("Multiple source files found matching: \"%s.\"\n",
m_options.file_name.c_str());
result.SetStatus (eReturnStatusFailed);
return false;
@@ -891,16 +891,16 @@ protected:
OptionDefinition
CommandObjectSourceList::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_ALL, false, "count", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount, "The number of source lines to display."},
+{ LLDB_OPT_SET_ALL, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCount, "The number of source lines to display."},
{ LLDB_OPT_SET_1 |
- LLDB_OPT_SET_2 , false, "shlib", 's', OptionParser::eRequiredArgument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source file in the given shared library."},
-{ LLDB_OPT_SET_ALL, false, "show-breakpoints", 'b', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Show the line table locations from the debug information that indicate valid places to set source level breakpoints."},
-{ LLDB_OPT_SET_1 , false, "file", 'f', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."},
-{ LLDB_OPT_SET_1 , false, "line", 'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeLineNum, "The line number at which to start the display source."},
-{ LLDB_OPT_SET_2 , false, "name", 'n', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeSymbol, "The name of a function whose source to display."},
-{ LLDB_OPT_SET_3 , false, "address",'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeAddressOrExpression, "Lookup the address and display the source information for the corresponding file and line."},
-{ LLDB_OPT_SET_4, false, "reverse", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Reverse the listing to look backwards from the last displayed block of source."},
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ LLDB_OPT_SET_2 , false, "shlib", 's', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source file in the given shared library."},
+{ LLDB_OPT_SET_ALL, false, "show-breakpoints", 'b', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Show the line table locations from the debug information that indicate valid places to set source level breakpoints."},
+{ LLDB_OPT_SET_1 , false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."},
+{ LLDB_OPT_SET_1 , false, "line", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLineNum, "The line number at which to start the display source."},
+{ LLDB_OPT_SET_2 , false, "name", 'n', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSymbolCompletion, eArgTypeSymbol, "The name of a function whose source to display."},
+{ LLDB_OPT_SET_3 , false, "address",'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeAddressOrExpression, "Lookup the address and display the source information for the corresponding file and line."},
+{ LLDB_OPT_SET_4, false, "reverse", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Reverse the listing to look backwards from the last displayed block of source."},
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#pragma mark CommandObjectMultiwordSource
diff --git a/source/Commands/CommandObjectTarget.cpp b/source/Commands/CommandObjectTarget.cpp
index 308b72f355d3..024f7b5a0415 100644
--- a/source/Commands/CommandObjectTarget.cpp
+++ b/source/Commands/CommandObjectTarget.cpp
@@ -63,18 +63,18 @@ static void
DumpTargetInfo (uint32_t target_idx, Target *target, const char *prefix_cstr, bool show_stopped_process_status, Stream &strm)
{
const ArchSpec &target_arch = target->GetArchitecture();
-
+
Module *exe_module = target->GetExecutableModulePointer();
char exe_path[PATH_MAX];
bool exe_valid = false;
if (exe_module)
exe_valid = exe_module->GetFileSpec().GetPath (exe_path, sizeof(exe_path));
-
+
if (!exe_valid)
::strcpy (exe_path, "<none>");
-
+
strm.Printf ("%starget #%u: %s", prefix_cstr ? prefix_cstr : "", target_idx, exe_path);
-
+
uint32_t properties = 0;
if (target_arch.IsValid())
{
@@ -84,7 +84,7 @@ DumpTargetInfo (uint32_t target_idx, Target *target, const char *prefix_cstr, bo
PlatformSP platform_sp (target->GetPlatform());
if (platform_sp)
strm.Printf ("%splatform=%s", properties++ > 0 ? ", " : " ( ", platform_sp->GetName().GetCString());
-
+
ProcessSP process_sp (target->GetProcessSP());
bool show_process_status = false;
if (process_sp)
@@ -123,7 +123,7 @@ DumpTargetList (TargetList &target_list, bool show_stopped_process_status, Strea
{
const uint32_t num_targets = target_list.GetNumTargets();
if (num_targets)
- {
+ {
TargetSP selected_target_sp (target_list.GetSelectedTarget());
strm.PutCString ("Current targets:\n");
for (uint32_t i=0; i<num_targets; ++i)
@@ -167,17 +167,17 @@ public:
{
CommandArgumentEntry arg;
CommandArgumentData file_arg;
-
+
// Define the first (and only) variant of this arg.
file_arg.arg_type = eArgTypeFilename;
file_arg.arg_repetition = eArgRepeatPlain;
-
+
// There is only one variant this argument could be; put it into the argument entry.
arg.push_back (file_arg);
-
+
// Push the data for the first argument into the m_arguments vector.
m_arguments.push_back (arg);
-
+
m_option_group.Append (&m_arch_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Append (&m_platform_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Append (&m_core_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
@@ -210,7 +210,7 @@ public:
{
std::string completion_str (input.GetArgumentAtIndex(cursor_index));
completion_str.erase (cursor_char_position);
-
+
CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
CommandCompletions::eDiskFileCompletion,
completion_str.c_str(),
@@ -230,12 +230,38 @@ protected:
FileSpec core_file (m_core_file.GetOptionValue().GetCurrentValue());
FileSpec remote_file (m_remote_file.GetOptionValue().GetCurrentValue());
+ if (core_file)
+ {
+ if (!core_file.Exists())
+ {
+ result.AppendErrorWithFormat("core file '%s' doesn't exist", core_file.GetPath().c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+
+ }
+ if (!core_file.Readable())
+ {
+ result.AppendErrorWithFormat("core file '%s' is not readable", core_file.GetPath().c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
if (argc == 1 || core_file || remote_file)
{
FileSpec symfile (m_symbol_file.GetOptionValue().GetCurrentValue());
if (symfile)
{
- if (!symfile.Exists())
+ if (symfile.Exists())
+ {
+ if (!symfile.Readable())
+ {
+ result.AppendErrorWithFormat("symbol file '%s' is not readable", core_file.GetPath().c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
{
char symfile_path[PATH_MAX];
symfile.GetPath(symfile_path, sizeof(symfile_path));
@@ -248,12 +274,12 @@ protected:
const char *file_path = command.GetArgumentAtIndex(0);
Timer scoped_timer(__PRETTY_FUNCTION__, "(lldb) target create '%s'", file_path);
FileSpec file_spec;
-
+
if (file_path)
file_spec.SetFile (file_path, true);
-
+
bool must_set_platform_path = false;
-
+
Debugger &debugger = m_interpreter.GetDebugger();
PlatformSP platform_sp(debugger.GetPlatformList().GetSelectedPlatform ());
@@ -334,7 +360,7 @@ protected:
}
}
}
-
+
debugger.GetTargetList().SetSelectedTarget(target_sp.get());
if (must_set_platform_path)
{
@@ -352,7 +378,7 @@ protected:
FileSpec core_file_dir;
core_file_dir.GetDirectory() = core_file.GetDirectory();
target_sp->GetExecutableSearchPaths ().Append (core_file_dir);
-
+
ProcessSP process_sp (target_sp->CreateProcess (m_interpreter.GetDebugger().GetListener(), NULL, &core_file));
if (process_sp)
@@ -360,7 +386,7 @@ protected:
// Seems wierd that we Launch a core file, but that is
// what we do!
error = process_sp->LoadCore();
-
+
if (error.Fail())
{
result.AppendError(error.AsCString("can't find plug-in for core file"));
@@ -403,7 +429,6 @@ protected:
result.SetStatus (eReturnStatusFailed);
}
return result.Succeeded();
-
}
private:
@@ -434,12 +459,12 @@ public:
0)
{
}
-
+
virtual
~CommandObjectTargetList ()
{
}
-
+
protected:
virtual bool
DoExecute (Args& args, CommandReturnObject &result)
@@ -447,7 +472,7 @@ protected:
if (args.GetArgumentCount() == 0)
{
Stream &strm = result.GetOutputStream();
-
+
bool show_stopped_process_status = false;
if (DumpTargetList (m_interpreter.GetDebugger().GetTargetList(), show_stopped_process_status, strm) == 0)
{
@@ -482,12 +507,12 @@ public:
0)
{
}
-
+
virtual
~CommandObjectTargetSelect ()
{
}
-
+
protected:
virtual bool
DoExecute (Args& args, CommandReturnObject &result)
@@ -520,9 +545,16 @@ protected:
}
else
{
- result.AppendErrorWithFormat ("index %u is out of range, valid target indexes are 0 - %u\n",
- target_idx,
- num_targets - 1);
+ if (num_targets > 0)
+ {
+ result.AppendErrorWithFormat ("index %u is out of range, valid target indexes are 0 - %u\n",
+ target_idx,
+ num_targets - 1);
+ } else
+ {
+ result.AppendErrorWithFormat ("index %u is out of range since there are no active targets\n",
+ target_idx);
+ }
result.SetStatus (eReturnStatusFailed);
}
}
@@ -562,12 +594,12 @@ public:
m_option_group.Append (&m_cleanup_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Finalize();
}
-
+
virtual
~CommandObjectTargetDelete ()
{
}
-
+
Options *
GetOptions ()
{
@@ -600,7 +632,7 @@ protected:
if (success)
{
if (target_idx < num_targets)
- {
+ {
target_sp = target_list.GetTargetAtIndex (target_idx);
if (target_sp)
{
@@ -626,7 +658,6 @@ protected:
success = false;
}
}
-
}
else
{
@@ -661,10 +692,10 @@ protected:
result.GetOutputStream().Printf("%u targets deleted.\n", (uint32_t)num_targets_to_delete);
result.SetStatus(eReturnStatusSuccessFinishResult);
}
-
+
return result.Succeeded();
}
-
+
OptionGroupOptions m_option_group;
OptionGroupBoolean m_cleanup_option;
};
@@ -678,6 +709,9 @@ protected:
class CommandObjectTargetVariable : public CommandObjectParsed
{
+ static const uint32_t SHORT_OPTION_FILE = 0x66696c65; // 'file'
+ static const uint32_t SHORT_OPTION_SHLB = 0x73686c62; // 'shlb'
+
public:
CommandObjectTargetVariable (CommandInterpreter &interpreter) :
CommandObjectParsed (interpreter,
@@ -688,23 +722,27 @@ public:
m_option_group (interpreter),
m_option_variable (false), // Don't include frame options
m_option_format (eFormatDefault),
- m_option_compile_units (LLDB_OPT_SET_1, false, "file", 'file', 0, eArgTypeFilename, "A basename or fullpath to a file that contains global variables. This option can be specified multiple times."),
- m_option_shared_libraries (LLDB_OPT_SET_1, false, "shlib",'shlb', 0, eArgTypeFilename, "A basename or fullpath to a shared library to use in the search for global variables. This option can be specified multiple times."),
+ m_option_compile_units (LLDB_OPT_SET_1, false, "file",
+ SHORT_OPTION_FILE, 0, eArgTypeFilename,
+ "A basename or fullpath to a file that contains global variables. This option can be specified multiple times."),
+ m_option_shared_libraries (LLDB_OPT_SET_1, false, "shlib",
+ SHORT_OPTION_SHLB, 0, eArgTypeFilename,
+ "A basename or fullpath to a shared library to use in the search for global variables. This option can be specified multiple times."),
m_varobj_options()
{
CommandArgumentEntry arg;
CommandArgumentData var_name_arg;
-
+
// Define the first (and only) variant of this arg.
var_name_arg.arg_type = eArgTypeVarName;
var_name_arg.arg_repetition = eArgRepeatPlus;
-
+
// There is only one variant this argument could be; put it into the argument entry.
arg.push_back (var_name_arg);
-
+
// Push the data for the first argument into the m_arguments vector.
m_arguments.push_back (arg);
-
+
m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Append (&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Append (&m_option_format, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1);
@@ -712,7 +750,7 @@ public:
m_option_group.Append (&m_option_shared_libraries, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Finalize();
}
-
+
virtual
~CommandObjectTargetVariable ()
{
@@ -722,33 +760,33 @@ public:
DumpValueObject (Stream &s, VariableSP &var_sp, ValueObjectSP &valobj_sp, const char *root_name)
{
DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions());
-
+
switch (var_sp->GetScope())
{
case eValueTypeVariableGlobal:
if (m_option_variable.show_scope)
s.PutCString("GLOBAL: ");
break;
-
+
case eValueTypeVariableStatic:
if (m_option_variable.show_scope)
s.PutCString("STATIC: ");
break;
-
+
case eValueTypeVariableArgument:
if (m_option_variable.show_scope)
s.PutCString(" ARG: ");
break;
-
+
case eValueTypeVariableLocal:
if (m_option_variable.show_scope)
s.PutCString(" LOCAL: ");
break;
-
+
default:
break;
}
-
+
if (m_option_variable.show_decl)
{
bool show_fullpaths = false;
@@ -756,17 +794,16 @@ public:
if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module))
s.PutCString (": ");
}
-
+
const Format format = m_option_format.GetFormat();
if (format != eFormatDefault)
options.SetFormat(format);
options.SetRootValueObjectName(root_name);
-
+
valobj_sp->Dump(s,options);
}
-
-
+
static size_t GetVariableCallback (void *baton,
const char *name,
VariableList &variable_list)
@@ -781,17 +818,14 @@ public:
}
return 0;
}
-
-
Options *
GetOptions ()
{
return &m_option_group;
}
-
+
protected:
-
void
DumpGlobalVariableList(const ExecutionContext &exe_ctx, const SymbolContext &sc, const VariableList &variable_list, Stream &s)
{
@@ -817,14 +851,14 @@ protected:
s.Printf ("Global variables for %s\n",
sc.comp_unit->GetPath().c_str());
}
-
+
for (uint32_t i=0; i<count; ++i)
{
VariableSP var_sp (variable_list.GetVariableAtIndex(i));
if (var_sp)
{
ValueObjectSP valobj_sp (ValueObjectVariable::Create (exe_ctx.GetBestExecutionContextScope(), var_sp));
-
+
if (valobj_sp)
DumpValueObject (s, var_sp, valobj_sp, var_sp->GetName().GetCString());
}
@@ -838,7 +872,7 @@ protected:
Target *target = m_exe_ctx.GetTargetPtr();
const size_t argc = args.GetArgumentCount();
Stream &s = result.GetOutputStream();
-
+
if (argc > 0)
{
@@ -875,7 +909,7 @@ protected:
valobj_list));
matches = variable_list.GetSize();
}
-
+
if (matches == 0)
{
result.GetErrorStream().Printf ("error: can't find global variable '%s'\n", arg);
@@ -892,7 +926,7 @@ protected:
ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(global_idx));
if (!valobj_sp)
valobj_sp = ValueObjectVariable::Create (m_exe_ctx.GetBestExecutionContextScope(), var_sp);
-
+
if (valobj_sp)
DumpValueObject (s, var_sp, valobj_sp, use_var_name ? var_sp->GetName().GetCString() : arg);
}
@@ -939,7 +973,7 @@ protected:
comp_unit->GetPath().c_str());
else
result.AppendErrorWithFormat ("no debug information for frame %u\n", frame->GetFrameIndex());
- }
+ }
else
result.AppendError ("'target variable' takes one or more global variable names as arguments\n");
result.SetStatus (eReturnStatusFailed);
@@ -956,7 +990,7 @@ protected:
{
const FileSpec module_file(shlibs.GetFileSpecAtIndex(shlib_idx));
ModuleSpec module_spec (module_file);
-
+
ModuleSP module_sp (target->GetImages().FindFirstModule(module_spec));
if (module_sp)
{
@@ -986,7 +1020,7 @@ protected:
for (size_t cu_idx=0; cu_idx<num_compile_units; ++cu_idx)
target->GetImages().FindCompileUnits(compile_units.GetFileSpecAtIndex(cu_idx), append, sc_list);
}
-
+
const uint32_t num_scs = sc_list.GetSize();
if (num_scs > 0)
{
@@ -1022,10 +1056,10 @@ protected:
m_cmd_name.c_str());
m_interpreter.TruncationWarningGiven();
}
-
+
return result.Succeeded();
}
-
+
OptionGroupOptions m_option_group;
OptionGroupVariable m_option_variable;
OptionGroupFormat m_option_format;
@@ -1051,15 +1085,15 @@ public:
CommandArgumentEntry arg;
CommandArgumentData old_prefix_arg;
CommandArgumentData new_prefix_arg;
-
+
// Define the first variant of this arg pair.
old_prefix_arg.arg_type = eArgTypeOldPathPrefix;
old_prefix_arg.arg_repetition = eArgRepeatPairPlus;
-
+
// Define the first variant of this arg pair.
new_prefix_arg.arg_type = eArgTypeNewPathPrefix;
new_prefix_arg.arg_repetition = eArgRepeatPairPlus;
-
+
// There are two required arguments that must always occur together, i.e. an argument "pair". Because they
// must always occur together, they are treated as two variants of one argument rather than two independent
// arguments. Push them both into the first argument position for m_arguments...
@@ -1094,7 +1128,7 @@ protected:
{
const char *from = command.GetArgumentAtIndex(i);
const char *to = command.GetArgumentAtIndex(i+1);
-
+
if (from[0] && to[0])
{
bool last_pair = ((argc - i) == 2);
@@ -1179,7 +1213,7 @@ public:
CommandArgumentData index_arg;
CommandArgumentData old_prefix_arg;
CommandArgumentData new_prefix_arg;
-
+
// Define the first and only variant of this arg.
index_arg.arg_type = eArgTypeIndex;
index_arg.arg_repetition = eArgRepeatPlain;
@@ -1190,11 +1224,11 @@ public:
// Define the first variant of this arg pair.
old_prefix_arg.arg_type = eArgTypeOldPathPrefix;
old_prefix_arg.arg_repetition = eArgRepeatPairPlus;
-
+
// Define the first variant of this arg pair.
new_prefix_arg.arg_type = eArgTypeNewPathPrefix;
new_prefix_arg.arg_repetition = eArgRepeatPairPlus;
-
+
// There are two required arguments that must always occur together, i.e. an argument "pair". Because they
// must always occur together, they are treated as two variants of one argument rather than two independent
// arguments. Push them both into the same argument position for m_arguments...
@@ -1242,7 +1276,7 @@ protected:
{
const char *from = command.GetArgumentAtIndex(i);
const char *to = command.GetArgumentAtIndex(i+1);
-
+
if (from[0] && to[0])
{
bool last_pair = ((argc - i) == 2);
@@ -1341,14 +1375,14 @@ public:
{
CommandArgumentEntry arg;
CommandArgumentData path_arg;
-
+
// Define the first (and only) variant of this arg.
path_arg.arg_type = eArgTypeDirectoryName;
path_arg.arg_repetition = eArgRepeatPlain;
-
+
// There is only one variant this argument could be; put it into the argument entry.
arg.push_back (path_arg);
-
+
// Push the data for the first argument into the m_arguments vector.
m_arguments.push_back (arg);
}
@@ -1435,7 +1469,7 @@ DumpCompileUnitLineTable (CommandInterpreter &interpreter,
false,
eSymbolContextCompUnit,
sc_list);
-
+
for (uint32_t i=0; i<num_matches; ++i)
{
SymbolContext sc;
@@ -1443,7 +1477,7 @@ DumpCompileUnitLineTable (CommandInterpreter &interpreter,
{
if (i > 0)
strm << "\n\n";
-
+
strm << "Line table for " << *static_cast<FileSpec*> (sc.comp_unit) << " in `"
<< module->GetFileSpec().GetFilename() << "\n";
LineTable *line_table = sc.comp_unit->GetLineTable();
@@ -1612,7 +1646,7 @@ LookupAddressInModule (CommandInterpreter &interpreter,
if (!module->ResolveFileAddress (addr, so_addr))
return false;
}
-
+
ExecutionContextScope *exe_scope = interpreter.GetExecutionContext().GetBestExecutionContextScope();
DumpAddress (exe_scope, so_addr, verbose, strm);
// strm.IndentMore();
@@ -1635,7 +1669,7 @@ LookupAddressInModule (CommandInterpreter &interpreter,
// strm.IndentLess();
return true;
}
-
+
return false;
}
@@ -1645,7 +1679,7 @@ LookupSymbolInModule (CommandInterpreter &interpreter, Stream &strm, Module *mod
if (module)
{
SymbolContext sc;
-
+
SymbolVendor *sym_vendor = module->GetSymbolVendor ();
if (sym_vendor)
{
@@ -1667,8 +1701,7 @@ LookupSymbolInModule (CommandInterpreter &interpreter, Stream &strm, Module *mod
{
num_matches = symtab->AppendSymbolIndexesWithName (symbol_name, match_indexes);
}
-
-
+
if (num_matches > 0)
{
strm.Indent ();
@@ -1705,19 +1738,19 @@ DumpSymbolContextList (ExecutionContextScope *exe_scope, Stream &strm, SymbolCon
strm.IndentMore ();
uint32_t i;
const uint32_t num_matches = sc_list.GetSize();
-
+
for (i=0; i<num_matches; ++i)
{
SymbolContext sc;
if (sc_list.GetContextAtIndex(i, sc))
{
AddressRange range;
-
+
sc.GetAddressRange(eSymbolContextEverything,
0,
true,
range);
-
+
DumpAddress (exe_scope, range.GetBaseAddress(), verbose, strm);
}
}
@@ -1759,11 +1792,11 @@ LookupFunctionInModule (CommandInterpreter &interpreter,
append,
sc_list);
}
-
+
if (num_matches)
{
strm.Indent ();
- strm.Printf("%zu match%s found in ", num_matches, num_matches > 1 ? "es" : "");
+ strm.Printf("%" PRIu64 " match%s found in ", (uint64_t)num_matches, num_matches > 1 ? "es" : "");
DumpFullpath (strm, &module->GetFileSpec(), 0);
strm.PutCString(":\n");
DumpSymbolContextList (interpreter.GetExecutionContext().GetBestExecutionContextScope(), strm, sc_list, verbose);
@@ -1790,11 +1823,11 @@ LookupTypeInModule (CommandInterpreter &interpreter,
ConstString name(name_cstr);
num_matches = module->FindTypes(sc, name, name_is_fully_qualified, max_num_matches, type_list);
-
+
if (num_matches)
{
strm.Indent ();
- strm.Printf("%zu match%s found in ", num_matches, num_matches > 1 ? "es" : "");
+ strm.Printf("%" PRIu64 " match%s found in ", (uint64_t)num_matches, num_matches > 1 ? "es" : "");
DumpFullpath (strm, &module->GetFileSpec(), 0);
strm.PutCString(":\n");
for (TypeSP type_sp : type_list.Types())
@@ -1835,22 +1868,22 @@ LookupTypeHere (CommandInterpreter &interpreter,
{
if (!sym_ctx.module_sp)
return 0;
-
+
TypeList type_list;
const uint32_t max_num_matches = UINT32_MAX;
size_t num_matches = 1;
bool name_is_fully_qualified = false;
-
+
ConstString name(name_cstr);
num_matches = sym_ctx.module_sp->FindTypes(sym_ctx, name, name_is_fully_qualified, max_num_matches, type_list);
-
+
if (num_matches)
{
strm.Indent ();
strm.PutCString("Best match found in ");
DumpFullpath (strm, &sym_ctx.module_sp->GetFileSpec(), 0);
strm.PutCString(":\n");
-
+
TypeSP type_sp (type_list.GetTypeAtIndex(0));
if (type_sp)
{
@@ -1905,7 +1938,6 @@ LookupFileAndLineInModule (CommandInterpreter &interpreter,
}
}
return 0;
-
}
@@ -1918,7 +1950,7 @@ FindModulesByName (Target *target,
// Dump specified images (by basename or fullpath)
FileSpec module_file_spec(module_name, false);
ModuleSpec module_spec (module_file_spec);
-
+
const size_t initial_size = module_list.GetSize ();
if (check_global_list)
@@ -1930,7 +1962,7 @@ FindModulesByName (Target *target,
for (size_t image_idx = 0; image_idx<num_modules; ++image_idx)
{
Module *module = Module::GetAllocatedModuleAtIndex(image_idx);
-
+
if (module)
{
if (module->MatchesModuleSpec (module_spec))
@@ -1946,7 +1978,7 @@ FindModulesByName (Target *target,
if (target)
{
const size_t num_matches = target->GetImages().FindModules (module_spec, module_list);
-
+
// Not found in our module list for our target, check the main
// shared module list in case it is a extra file used somewhere
// else
@@ -1961,7 +1993,7 @@ FindModulesByName (Target *target,
ModuleList::FindSharedModules (module_spec,module_list);
}
}
-
+
return module_list.GetSize () - initial_size;
}
@@ -1975,7 +2007,6 @@ FindModulesByName (Target *target,
class CommandObjectTargetModulesModuleAutoComplete : public CommandObjectParsed
{
public:
-
CommandObjectTargetModulesModuleAutoComplete (CommandInterpreter &interpreter,
const char *name,
const char *help,
@@ -1984,23 +2015,23 @@ public:
{
CommandArgumentEntry arg;
CommandArgumentData file_arg;
-
+
// Define the first (and only) variant of this arg.
file_arg.arg_type = eArgTypeFilename;
file_arg.arg_repetition = eArgRepeatStar;
-
+
// There is only one variant this argument could be; put it into the argument entry.
arg.push_back (file_arg);
-
+
// Push the data for the first argument into the m_arguments vector.
m_arguments.push_back (arg);
}
-
+
virtual
~CommandObjectTargetModulesModuleAutoComplete ()
{
}
-
+
virtual int
HandleArgumentCompletion (Args &input,
int &cursor_index,
@@ -2014,7 +2045,7 @@ public:
// Arguments are the standard module completer.
std::string completion_str (input.GetArgumentAtIndex(cursor_index));
completion_str.erase (cursor_char_position);
-
+
CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
CommandCompletions::eModuleCompletion,
completion_str.c_str(),
@@ -2037,7 +2068,6 @@ public:
class CommandObjectTargetModulesSourceFileAutoComplete : public CommandObjectParsed
{
public:
-
CommandObjectTargetModulesSourceFileAutoComplete (CommandInterpreter &interpreter,
const char *name,
const char *help,
@@ -2047,23 +2077,23 @@ public:
{
CommandArgumentEntry arg;
CommandArgumentData source_file_arg;
-
+
// Define the first (and only) variant of this arg.
source_file_arg.arg_type = eArgTypeSourceFile;
source_file_arg.arg_repetition = eArgRepeatPlus;
-
+
// There is only one variant this argument could be; put it into the argument entry.
arg.push_back (source_file_arg);
-
+
// Push the data for the first argument into the m_arguments vector.
m_arguments.push_back (arg);
}
-
+
virtual
~CommandObjectTargetModulesSourceFileAutoComplete ()
{
}
-
+
virtual int
HandleArgumentCompletion (Args &input,
int &cursor_index,
@@ -2077,7 +2107,7 @@ public:
// Arguments are the standard source file completer.
std::string completion_str (input.GetArgumentAtIndex(cursor_index));
completion_str.erase (cursor_char_position);
-
+
CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
CommandCompletions::eSourceFileCompletion,
completion_str.c_str(),
@@ -2105,39 +2135,38 @@ public:
m_options (interpreter)
{
}
-
+
virtual
~CommandObjectTargetModulesDumpSymtab ()
{
}
-
+
virtual Options *
GetOptions ()
{
return &m_options;
}
-
+
class CommandOptions : public Options
{
public:
-
CommandOptions (CommandInterpreter &interpreter) :
Options(interpreter),
m_sort_order (eSortOrderNone)
{
}
-
+
virtual
~CommandOptions ()
{
}
-
+
virtual Error
SetOptionValue (uint32_t option_idx, const char *option_arg)
{
Error error;
const int short_option = m_getopt_table[option_idx].val;
-
+
switch (short_option)
{
case 's':
@@ -2146,33 +2175,33 @@ public:
eSortOrderNone,
error);
break;
-
+
default:
error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
break;
-
+
}
return error;
}
-
+
void
OptionParsingStarting ()
{
m_sort_order = eSortOrderNone;
}
-
+
const OptionDefinition*
GetDefinitions ()
{
return g_option_table;
}
-
+
// Options table: Required for subclasses of Options.
static OptionDefinition g_option_table[];
-
+
SortOrder m_sort_order;
};
-
+
protected:
virtual bool
DoExecute (Args& command,
@@ -2188,11 +2217,11 @@ protected:
else
{
uint32_t num_dumped = 0;
-
+
uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
result.GetOutputStream().SetAddressByteSize(addr_byte_size);
result.GetErrorStream().SetAddressByteSize(addr_byte_size);
-
+
if (command.GetArgumentCount() == 0)
{
// Dump all sections for all modules images
@@ -2200,7 +2229,7 @@ protected:
const size_t num_modules = target->GetImages().GetSize();
if (num_modules > 0)
{
- result.GetOutputStream().Printf("Dumping symbol table for %zu modules.\n", num_modules);
+ result.GetOutputStream().Printf("Dumping symbol table for %" PRIu64 " modules.\n", (uint64_t)num_modules);
for (size_t image_idx = 0; image_idx<num_modules; ++image_idx)
{
if (num_dumped > 0)
@@ -2251,7 +2280,7 @@ protected:
result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr);
}
}
-
+
if (num_dumped > 0)
result.SetStatus (eReturnStatusSuccessFinishResult);
else
@@ -2262,8 +2291,7 @@ protected:
}
return result.Succeeded();
}
-
-
+
CommandOptions m_options;
};
@@ -2280,8 +2308,8 @@ g_sort_option_enumeration[4] =
OptionDefinition
CommandObjectTargetModulesDumpSymtab::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "sort", 's', OptionParser::eRequiredArgument, g_sort_option_enumeration, 0, eArgTypeSortOrder, "Supply a sort order when dumping the symbol table."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_1, false, "sort", 's', OptionParser::eRequiredArgument, NULL, g_sort_option_enumeration, 0, eArgTypeSortOrder, "Supply a sort order when dumping the symbol table."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#pragma mark CommandObjectTargetModulesDumpSections
@@ -2301,12 +2329,12 @@ public:
NULL)
{
}
-
+
virtual
~CommandObjectTargetModulesDumpSections ()
{
}
-
+
protected:
virtual bool
DoExecute (Args& command,
@@ -2322,18 +2350,18 @@ protected:
else
{
uint32_t num_dumped = 0;
-
+
uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
result.GetOutputStream().SetAddressByteSize(addr_byte_size);
result.GetErrorStream().SetAddressByteSize(addr_byte_size);
-
+
if (command.GetArgumentCount() == 0)
{
// Dump all sections for all modules images
const size_t num_modules = target->GetImages().GetSize();
if (num_modules > 0)
{
- result.GetOutputStream().Printf("Dumping sections for %zu modules.\n", num_modules);
+ result.GetOutputStream().Printf("Dumping sections for %" PRIu64 " modules.\n", (uint64_t)num_modules);
for (size_t image_idx = 0; image_idx<num_modules; ++image_idx)
{
num_dumped++;
@@ -2376,7 +2404,7 @@ protected:
}
}
}
-
+
if (num_dumped > 0)
result.SetStatus (eReturnStatusSuccessFinishResult);
else
@@ -2407,12 +2435,12 @@ public:
NULL)
{
}
-
+
virtual
~CommandObjectTargetModulesDumpSymfile ()
{
}
-
+
protected:
virtual bool
DoExecute (Args& command,
@@ -2428,11 +2456,11 @@ protected:
else
{
uint32_t num_dumped = 0;
-
+
uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
result.GetOutputStream().SetAddressByteSize(addr_byte_size);
result.GetErrorStream().SetAddressByteSize(addr_byte_size);
-
+
if (command.GetArgumentCount() == 0)
{
// Dump all sections for all modules images
@@ -2441,7 +2469,7 @@ protected:
const size_t num_modules = target_modules.GetSize();
if (num_modules > 0)
{
- result.GetOutputStream().Printf("Dumping debug symbols for %zu modules.\n", num_modules);
+ result.GetOutputStream().Printf("Dumping debug symbols for %" PRIu64 " modules.\n", (uint64_t)num_modules);
for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx)
{
if (DumpModuleSymbolVendor (result.GetOutputStream(), target_modules.GetModulePointerAtIndexUnlocked(image_idx)))
@@ -2479,7 +2507,7 @@ protected:
result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr);
}
}
-
+
if (num_dumped > 0)
result.SetStatus (eReturnStatusSuccessFinishResult);
else
@@ -2510,12 +2538,12 @@ public:
eFlagRequiresTarget)
{
}
-
+
virtual
~CommandObjectTargetModulesDumpLineTable ()
{
}
-
+
protected:
virtual bool
DoExecute (Args& command,
@@ -2523,11 +2551,11 @@ protected:
{
Target *target = m_exe_ctx.GetTargetPtr();
uint32_t total_num_dumped = 0;
-
+
uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
result.GetOutputStream().SetAddressByteSize(addr_byte_size);
result.GetErrorStream().SetAddressByteSize(addr_byte_size);
-
+
if (command.GetArgumentCount() == 0)
{
result.AppendErrorWithFormat ("\nSyntax: %s\n", m_cmd_syntax.c_str());
@@ -2540,7 +2568,7 @@ protected:
for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
{
FileSpec file_spec(arg_cstr, false);
-
+
const ModuleList &target_modules = target->GetImages();
Mutex::Locker modules_locker(target_modules.GetMutex());
const size_t num_modules = target_modules.GetSize();
@@ -2563,7 +2591,7 @@ protected:
}
}
}
-
+
if (total_num_dumped > 0)
result.SetStatus (eReturnStatusSuccessFinishResult);
else
@@ -2585,7 +2613,6 @@ protected:
class CommandObjectTargetModulesDump : public CommandObjectMultiword
{
public:
-
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
@@ -2600,7 +2627,7 @@ public:
LoadSubCommand ("symfile", CommandObjectSP (new CommandObjectTargetModulesDumpSymfile (interpreter)));
LoadSubCommand ("line-table", CommandObjectSP (new CommandObjectTargetModulesDumpLineTable (interpreter)));
}
-
+
virtual
~CommandObjectTargetModulesDump()
{
@@ -2622,18 +2649,18 @@ public:
m_option_group.Append (&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Finalize();
}
-
+
virtual
~CommandObjectTargetModulesAdd ()
{
}
-
+
virtual Options *
GetOptions ()
{
return &m_option_group;
}
-
+
virtual int
HandleArgumentCompletion (Args &input,
int &cursor_index,
@@ -2646,7 +2673,7 @@ public:
{
std::string completion_str (input.GetArgumentAtIndex(cursor_index));
completion_str.erase (cursor_char_position);
-
+
CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
CommandCompletions::eDiskFileCompletion,
completion_str.c_str(),
@@ -2659,11 +2686,9 @@ public:
}
protected:
-
OptionGroupOptions m_option_group;
OptionGroupUUID m_uuid_option_group;
OptionGroupFile m_symbol_file;
-
virtual bool
DoExecute (Args& args,
@@ -2679,7 +2704,7 @@ protected:
else
{
bool flush = false;
-
+
const size_t argc = args.GetArgumentCount();
if (argc == 0)
{
@@ -2700,8 +2725,6 @@ protected:
}
else
{
- flush = true;
-
StreamString strm;
module_spec.GetUUID().Dump (&strm);
if (module_spec.GetFileSpec())
@@ -2798,7 +2821,7 @@ protected:
}
}
}
-
+
if (flush)
{
ProcessSP process = target->GetProcessSP();
@@ -2806,7 +2829,7 @@ protected:
process->Flush();
}
}
-
+
return result.Succeeded();
}
@@ -2829,18 +2852,18 @@ public:
m_option_group.Append (&m_slide_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Finalize();
}
-
+
virtual
~CommandObjectTargetModulesLoad ()
{
}
-
+
virtual Options *
GetOptions ()
{
return &m_option_group;
}
-
+
protected:
virtual bool
DoExecute (Args& args,
@@ -2863,7 +2886,7 @@ protected:
search_using_module_spec = true;
module_spec.GetFileSpec() = m_file_option.GetOptionValue().GetCurrentValue();
}
-
+
if (m_uuid_option_group.GetOptionValue().OptionWasSet())
{
search_using_module_spec = true;
@@ -2872,7 +2895,6 @@ protected:
if (search_using_module_spec)
{
-
ModuleList matching_modules;
const size_t num_matches = target->GetImages().FindModules (module_spec, matching_modules);
@@ -2965,7 +2987,7 @@ protected:
}
}
}
-
+
if (changed)
{
target->ModulesDidLoad (matching_modules);
@@ -3004,7 +3026,7 @@ protected:
else
{
std::string uuid_str;
-
+
if (module_spec.GetFileSpec())
module_spec.GetFileSpec().GetPath (path, sizeof(path));
else
@@ -3044,8 +3066,8 @@ protected:
}
}
return result.Succeeded();
- }
-
+ }
+
OptionGroupOptions m_option_group;
OptionGroupUUID m_uuid_option_group;
OptionGroupFile m_file_option;
@@ -3058,11 +3080,9 @@ protected:
class CommandObjectTargetModulesList : public CommandObjectParsed
{
public:
-
class CommandOptions : public Options
{
public:
-
CommandOptions (CommandInterpreter &interpreter) :
Options(interpreter),
m_format_array(),
@@ -3070,12 +3090,12 @@ public:
m_module_addr (LLDB_INVALID_ADDRESS)
{
}
-
+
virtual
~CommandOptions ()
{
}
-
+
virtual Error
SetOptionValue (uint32_t option_idx, const char *option_arg)
{
@@ -3100,7 +3120,7 @@ public:
}
return error;
}
-
+
void
OptionParsingStarting ()
{
@@ -3108,24 +3128,24 @@ public:
m_use_global_module_list = false;
m_module_addr = LLDB_INVALID_ADDRESS;
}
-
+
const OptionDefinition*
GetDefinitions ()
{
return g_option_table;
}
-
+
// Options table: Required for subclasses of Options.
-
+
static OptionDefinition g_option_table[];
-
+
// Instance variables to hold the values for command options.
typedef std::vector< std::pair<char, uint32_t> > FormatWidthCollection;
FormatWidthCollection m_format_array;
bool m_use_global_module_list;
lldb::addr_t m_module_addr;
};
-
+
CommandObjectTargetModulesList (CommandInterpreter &interpreter) :
CommandObjectParsed (interpreter,
"target modules list",
@@ -3134,19 +3154,19 @@ public:
m_options (interpreter)
{
}
-
+
virtual
~CommandObjectTargetModulesList ()
{
}
-
+
virtual
Options *
GetOptions ()
{
return &m_options;
}
-
+
protected:
virtual bool
DoExecute (Args& command,
@@ -3174,7 +3194,7 @@ protected:
}
// Dump all sections for all modules images
Stream &strm = result.GetOutputStream();
-
+
if (m_options.m_module_addr != LLDB_INVALID_ADDRESS)
{
if (target)
@@ -3207,7 +3227,7 @@ protected:
}
return result.Succeeded();
}
-
+
size_t num_modules = 0;
Mutex::Locker locker; // This locker will be locked on the mutex in module_list_ptr if it is non-NULL.
// Otherwise it will lock the AllocationModuleCollectionMutex when accessing
@@ -3243,10 +3263,10 @@ protected:
}
}
}
-
+
module_list_ptr = &module_list;
}
-
+
if (module_list_ptr != NULL)
{
locker.Lock(module_list_ptr->GetMutex());
@@ -3254,7 +3274,7 @@ protected:
}
if (num_modules > 0)
- {
+ {
for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx)
{
ModuleSP module_sp;
@@ -3269,7 +3289,7 @@ protected:
module = Module::GetAllocatedModuleAtIndex(image_idx);
module_sp = module->shared_from_this();
}
-
+
const size_t indent = strm.Printf("[%3u] ", image_idx);
PrintModule (target, module, indent, strm);
@@ -3308,7 +3328,7 @@ protected:
strm.PutCString("Null module");
return;
}
-
+
bool dump_object_name = false;
if (m_options.m_format_array.empty())
{
@@ -3331,25 +3351,25 @@ protected:
case 'A':
DumpModuleArchitecture (strm, module, false, width);
break;
-
+
case 't':
DumpModuleArchitecture (strm, module, true, width);
break;
-
+
case 'f':
DumpFullpath (strm, &module->GetFileSpec(), width);
dump_object_name = true;
break;
-
+
case 'd':
DumpDirectory (strm, &module->GetFileSpec(), width);
break;
-
+
case 'b':
DumpBasename (strm, &module->GetFileSpec(), width);
dump_object_name = true;
break;
-
+
case 'h':
case 'o':
// Image header address
@@ -3402,9 +3422,9 @@ protected:
ref_count = module_sp.use_count() - 1;
}
if (width)
- strm.Printf("{%*zu}", width, ref_count);
+ strm.Printf("{%*" PRIu64 "}", width, (uint64_t)ref_count);
else
- strm.Printf("{%zu}", ref_count);
+ strm.Printf("{%" PRIu64 "}", (uint64_t)ref_count);
}
break;
@@ -3437,23 +3457,23 @@ protected:
strm.Printf("%.*s", width, "<NONE>");
}
break;
-
+
case 'm':
module->GetModificationTime().Dump(&strm, width);
break;
case 'p':
- strm.Printf("%p", module);
+ strm.Printf("%p", static_cast<void*>(module));
break;
case 'u':
DumpModuleUUID(strm, module);
break;
-
+
default:
break;
}
-
+
}
if (dump_object_name)
{
@@ -3463,29 +3483,29 @@ protected:
}
strm.EOL();
}
-
+
CommandOptions m_options;
};
OptionDefinition
CommandObjectTargetModulesList::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "address", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeAddressOrExpression, "Display the image at this address."},
- { LLDB_OPT_SET_1, false, "arch", 'A', OptionParser::eOptionalArgument, NULL, 0, eArgTypeWidth, "Display the architecture when listing images."},
- { LLDB_OPT_SET_1, false, "triple", 't', OptionParser::eOptionalArgument, NULL, 0, eArgTypeWidth, "Display the triple when listing images."},
- { LLDB_OPT_SET_1, false, "header", 'h', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Display the image header address as a load address if debugging, a file address otherwise."},
- { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Display the image header address offset from the header file address (the slide amount)."},
- { LLDB_OPT_SET_1, false, "uuid", 'u', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Display the UUID when listing images."},
- { LLDB_OPT_SET_1, false, "fullpath", 'f', OptionParser::eOptionalArgument, NULL, 0, eArgTypeWidth, "Display the fullpath to the image object file."},
- { LLDB_OPT_SET_1, false, "directory", 'd', OptionParser::eOptionalArgument, NULL, 0, eArgTypeWidth, "Display the directory with optional width for the image object file."},
- { LLDB_OPT_SET_1, false, "basename", 'b', OptionParser::eOptionalArgument, NULL, 0, eArgTypeWidth, "Display the basename with optional width for the image object file."},
- { LLDB_OPT_SET_1, false, "symfile", 's', OptionParser::eOptionalArgument, NULL, 0, eArgTypeWidth, "Display the fullpath to the image symbol file with optional width."},
- { LLDB_OPT_SET_1, false, "symfile-unique", 'S', OptionParser::eOptionalArgument, NULL, 0, eArgTypeWidth, "Display the symbol file with optional width only if it is different from the executable object file."},
- { LLDB_OPT_SET_1, false, "mod-time", 'm', OptionParser::eOptionalArgument, NULL, 0, eArgTypeWidth, "Display the modification time with optional width of the module."},
- { LLDB_OPT_SET_1, false, "ref-count", 'r', OptionParser::eOptionalArgument, NULL, 0, eArgTypeWidth, "Display the reference count if the module is still in the shared module cache."},
- { LLDB_OPT_SET_1, false, "pointer", 'p', OptionParser::eOptionalArgument, NULL, 0, eArgTypeNone, "Display the module pointer."},
- { LLDB_OPT_SET_1, false, "global", 'g', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Display the modules from the global module list, not just the current target."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_1, false, "address", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeAddressOrExpression, "Display the image at this address."},
+ { LLDB_OPT_SET_1, false, "arch", 'A', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeWidth, "Display the architecture when listing images."},
+ { LLDB_OPT_SET_1, false, "triple", 't', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeWidth, "Display the triple when listing images."},
+ { LLDB_OPT_SET_1, false, "header", 'h', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display the image header address as a load address if debugging, a file address otherwise."},
+ { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display the image header address offset from the header file address (the slide amount)."},
+ { LLDB_OPT_SET_1, false, "uuid", 'u', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display the UUID when listing images."},
+ { LLDB_OPT_SET_1, false, "fullpath", 'f', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeWidth, "Display the fullpath to the image object file."},
+ { LLDB_OPT_SET_1, false, "directory", 'd', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeWidth, "Display the directory with optional width for the image object file."},
+ { LLDB_OPT_SET_1, false, "basename", 'b', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeWidth, "Display the basename with optional width for the image object file."},
+ { LLDB_OPT_SET_1, false, "symfile", 's', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeWidth, "Display the fullpath to the image symbol file with optional width."},
+ { LLDB_OPT_SET_1, false, "symfile-unique", 'S', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeWidth, "Display the symbol file with optional width only if it is different from the executable object file."},
+ { LLDB_OPT_SET_1, false, "mod-time", 'm', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeWidth, "Display the modification time with optional width of the module."},
+ { LLDB_OPT_SET_1, false, "ref-count", 'r', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeWidth, "Display the reference count if the module is still in the shared module cache."},
+ { LLDB_OPT_SET_1, false, "pointer", 'p', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeNone, "Display the module pointer."},
+ { LLDB_OPT_SET_1, false, "global", 'g', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display the modules from the global module list, not just the current target."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#pragma mark CommandObjectTargetModulesShowUnwind
@@ -3584,7 +3604,7 @@ public:
std::string m_str; // Holds name lookup
lldb::addr_t m_addr; // Holds the address to lookup
};
-
+
CommandObjectTargetModulesShowUnwind (CommandInterpreter &interpreter) :
CommandObjectParsed (interpreter,
"target modules show-unwind",
@@ -3597,12 +3617,12 @@ public:
m_options (interpreter)
{
}
-
+
virtual
~CommandObjectTargetModulesShowUnwind ()
{
}
-
+
virtual
Options *
GetOptions ()
@@ -3645,7 +3665,7 @@ protected:
}
SymbolContextList sc_list;
-
+
if (m_options.m_type == eLookupTypeFunctionOrSymbol)
{
ConstString function_name (m_options.m_str.c_str());
@@ -3711,7 +3731,7 @@ protected:
result.GetOutputStream().Printf ("\n");
}
- UnwindPlanSP non_callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtNonCallSite(*thread.get());
+ UnwindPlanSP non_callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtNonCallSite(*target, *thread.get(), -1);
if (non_callsite_unwind_plan.get())
{
result.GetOutputStream().Printf("Asynchronous (not restricted to call-sites) UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
@@ -3755,9 +3775,9 @@ protected:
OptionDefinition
CommandObjectTargetModulesShowUnwind::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "name", 'n', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFunctionName, "Show unwind instructions for a function or symbol name."},
- { LLDB_OPT_SET_2, false, "address", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeAddressOrExpression, "Show unwind instructions for a function or symbol containing an address"},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_1, false, "name", 'n', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionName, "Show unwind instructions for a function or symbol name."},
+ { LLDB_OPT_SET_2, false, "address", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeAddressOrExpression, "Show unwind instructions for a function or symbol containing an address"},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//----------------------------------------------------------------------
@@ -3766,7 +3786,6 @@ CommandObjectTargetModulesShowUnwind::CommandOptions::g_option_table[] =
class CommandObjectTargetModulesLookup : public CommandObjectParsed
{
public:
-
enum
{
eLookupTypeInvalid = -1,
@@ -3778,29 +3797,28 @@ public:
eLookupTypeType,
kNumLookupTypes
};
-
+
class CommandOptions : public Options
{
public:
-
CommandOptions (CommandInterpreter &interpreter) :
Options(interpreter)
{
OptionParsingStarting();
}
-
+
virtual
~CommandOptions ()
{
}
-
+
virtual Error
SetOptionValue (uint32_t option_idx, const char *option_arg)
{
Error error;
-
+
const int short_option = m_getopt_table[option_idx].val;
-
+
switch (short_option)
{
case 'a':
@@ -3810,27 +3828,27 @@ public:
m_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
}
break;
-
+
case 'o':
m_offset = Args::StringToUInt64(option_arg, LLDB_INVALID_ADDRESS);
if (m_offset == LLDB_INVALID_ADDRESS)
error.SetErrorStringWithFormat ("invalid offset string '%s'", option_arg);
break;
-
+
case 's':
m_str = option_arg;
m_type = eLookupTypeSymbol;
break;
-
+
case 'f':
m_file.SetFile (option_arg, false);
m_type = eLookupTypeFileLine;
break;
-
+
case 'i':
m_include_inlines = false;
break;
-
+
case 'l':
m_line_number = Args::StringToUInt32(option_arg, UINT32_MAX);
if (m_line_number == UINT32_MAX)
@@ -3839,12 +3857,12 @@ public:
error.SetErrorString ("zero is an invalid line number");
m_type = eLookupTypeFileLine;
break;
-
+
case 'F':
m_str = option_arg;
m_type = eLookupTypeFunction;
break;
-
+
case 'n':
m_str = option_arg;
m_type = eLookupTypeFunctionOrSymbol;
@@ -3854,23 +3872,23 @@ public:
m_str = option_arg;
m_type = eLookupTypeType;
break;
-
+
case 'v':
m_verbose = 1;
break;
-
+
case 'A':
m_print_all = true;
break;
-
+
case 'r':
m_use_regex = true;
break;
}
-
+
return error;
}
-
+
void
OptionParsingStarting ()
{
@@ -3885,15 +3903,15 @@ public:
m_verbose = false;
m_print_all = false;
}
-
+
const OptionDefinition*
GetDefinitions ()
{
return g_option_table;
}
-
+
// Options table: Required for subclasses of Options.
-
+
static OptionDefinition g_option_table[];
int m_type; // Should be a eLookupTypeXXX enum after parsing options
std::string m_str; // Holds name lookup
@@ -3905,9 +3923,8 @@ public:
bool m_include_inlines;// Check for inline entries when looking up by file/line.
bool m_verbose; // Enable verbose lookup info
bool m_print_all; // Print all matches, even in cases where there's a best match.
-
};
-
+
CommandObjectTargetModulesLookup (CommandInterpreter &interpreter) :
CommandObjectParsed (interpreter,
"target modules lookup",
@@ -3918,29 +3935,29 @@ public:
{
CommandArgumentEntry arg;
CommandArgumentData file_arg;
-
+
// Define the first (and only) variant of this arg.
file_arg.arg_type = eArgTypeFilename;
file_arg.arg_repetition = eArgRepeatStar;
-
+
// There is only one variant this argument could be; put it into the argument entry.
arg.push_back (file_arg);
-
+
// Push the data for the first argument into the m_arguments vector.
m_arguments.push_back (arg);
}
-
+
virtual
~CommandObjectTargetModulesLookup ()
{
}
-
+
virtual Options *
GetOptions ()
{
return &m_options;
}
-
+
bool
LookupHere (CommandInterpreter &interpreter, CommandReturnObject &result, bool &syntax_error)
{
@@ -3956,17 +3973,17 @@ public:
case eLookupTypeType:
break;
}
-
+
StackFrameSP frame = m_exe_ctx.GetFrameSP();
-
+
if (!frame)
return false;
-
+
const SymbolContext &sym_ctx(frame->GetSymbolContext(eSymbolContextModule));
-
+
if (!sym_ctx.module_sp)
return false;
-
+
switch (m_options.m_type)
{
default:
@@ -3986,10 +4003,10 @@ public:
}
break;
}
-
+
return true;
}
-
+
bool
LookupInModule (CommandInterpreter &interpreter, Module *module, CommandReturnObject &result, bool &syntax_error)
{
@@ -4011,7 +4028,7 @@ public:
}
}
break;
-
+
case eLookupTypeSymbol:
if (!m_options.m_str.empty())
{
@@ -4027,11 +4044,10 @@ public:
}
}
break;
-
+
case eLookupTypeFileLine:
if (m_options.m_file)
{
-
if (LookupFileAndLineInModule (m_interpreter,
result.GetOutputStream(),
module,
@@ -4064,8 +4080,7 @@ public:
}
}
break;
-
-
+
case eLookupTypeType:
if (!m_options.m_str.empty())
{
@@ -4080,17 +4095,17 @@ public:
}
}
break;
-
+
default:
m_options.GenerateOptionUsage (result.GetErrorStream(), this);
syntax_error = true;
break;
}
-
+
result.SetStatus (eReturnStatusFailed);
return false;
}
-
+
protected:
virtual bool
DoExecute (Args& command,
@@ -4112,11 +4127,11 @@ protected:
result.GetOutputStream().SetAddressByteSize(addr_byte_size);
result.GetErrorStream().SetAddressByteSize(addr_byte_size);
// Dump all sections for all modules images
-
+
if (command.GetArgumentCount() == 0)
{
ModuleSP current_module;
-
+
// Where it is possible to look in the current symbol context
// first, try that. If this search was successful and --all
// was not passed, don't print anything else.
@@ -4130,9 +4145,9 @@ protected:
return result.Succeeded();
}
}
-
+
// Dump all sections for all other modules
-
+
const ModuleList &target_modules = target->GetImages();
Mutex::Locker modules_locker(target_modules.GetMutex());
const size_t num_modules = target_modules.GetSize();
@@ -4141,7 +4156,7 @@ protected:
for (i = 0; i<num_modules && syntax_error == false; ++i)
{
Module *module_pointer = target_modules.GetModulePointerAtIndexUnlocked(i);
-
+
if (module_pointer != current_module.get() &&
LookupInModule (m_interpreter, target_modules.GetModulePointerAtIndexUnlocked(i), result, syntax_error))
{
@@ -4184,7 +4199,7 @@ protected:
result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr);
}
}
-
+
if (num_successful_lookups > 0)
result.SetStatus (eReturnStatusSuccessFinishResult);
else
@@ -4192,29 +4207,29 @@ protected:
}
return result.Succeeded();
}
-
+
CommandOptions m_options;
};
OptionDefinition
CommandObjectTargetModulesLookup::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, true, "address", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeAddressOrExpression, "Lookup an address in one or more target modules."},
- { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOffset, "When looking up an address subtract <offset> from any addresses before doing the lookup."},
+ { LLDB_OPT_SET_1, true, "address", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeAddressOrExpression, "Lookup an address in one or more target modules."},
+ { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOffset, "When looking up an address subtract <offset> from any addresses before doing the lookup."},
{ LLDB_OPT_SET_2| LLDB_OPT_SET_4 | LLDB_OPT_SET_5
/* FIXME: re-enable this for types when the LookupTypeInModule actually uses the regex option: | LLDB_OPT_SET_6 */ ,
- false, "regex", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "The <name> argument for name lookups are regular expressions."},
- { LLDB_OPT_SET_2, true, "symbol", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeSymbol, "Lookup a symbol by name in the symbol tables in one or more target modules."},
- { LLDB_OPT_SET_3, true, "file", 'f', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename, "Lookup a file by fullpath or basename in one or more target modules."},
- { LLDB_OPT_SET_3, false, "line", 'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeLineNum, "Lookup a line number in a file (must be used in conjunction with --file)."},
+ false, "regex", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "The <name> argument for name lookups are regular expressions."},
+ { LLDB_OPT_SET_2, true, "symbol", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeSymbol, "Lookup a symbol by name in the symbol tables in one or more target modules."},
+ { LLDB_OPT_SET_3, true, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, "Lookup a file by fullpath or basename in one or more target modules."},
+ { LLDB_OPT_SET_3, false, "line", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLineNum, "Lookup a line number in a file (must be used in conjunction with --file)."},
{ LLDB_OPT_SET_FROM_TO(3,5),
- false, "no-inlines", 'i', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Ignore inline entries (must be used in conjunction with --file or --function)."},
- { LLDB_OPT_SET_4, true, "function", 'F', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFunctionName, "Lookup a function by name in the debug symbols in one or more target modules."},
- { LLDB_OPT_SET_5, true, "name", 'n', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFunctionOrSymbol, "Lookup a function or symbol by name in one or more target modules."},
- { LLDB_OPT_SET_6, true, "type", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Lookup a type by name in the debug symbols in one or more target modules."},
- { LLDB_OPT_SET_ALL, false, "verbose", 'v', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Enable verbose lookup information."},
- { LLDB_OPT_SET_ALL, false, "all", 'A', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Print all matches, not just the best match, if a best match is available."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ false, "no-inlines", 'i', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Ignore inline entries (must be used in conjunction with --file or --function)."},
+ { LLDB_OPT_SET_4, true, "function", 'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionName, "Lookup a function by name in the debug symbols in one or more target modules."},
+ { LLDB_OPT_SET_5, true, "name", 'n', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionOrSymbol, "Lookup a function or symbol by name in one or more target modules."},
+ { LLDB_OPT_SET_6, true, "type", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Lookup a type by name in the debug symbols in one or more target modules."},
+ { LLDB_OPT_SET_ALL, false, "verbose", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Enable verbose lookup information."},
+ { LLDB_OPT_SET_ALL, false, "all", 'A', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Print all matches, not just the best match, if a best match is available."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -4227,7 +4242,6 @@ CommandObjectTargetModulesLookup::CommandOptions::g_option_table[] =
class CommandObjectTargetModulesImageSearchPaths : public CommandObjectMultiword
{
public:
-
CommandObjectTargetModulesImageSearchPaths (CommandInterpreter &interpreter) :
CommandObjectMultiword (interpreter,
"target modules search-paths",
@@ -4240,7 +4254,7 @@ public:
LoadSubCommand ("list", CommandObjectSP (new CommandObjectTargetModulesSearchPathsList (interpreter)));
LoadSubCommand ("query", CommandObjectSP (new CommandObjectTargetModulesSearchPathsQuery (interpreter)));
}
-
+
~CommandObjectTargetModulesImageSearchPaths()
{
}
@@ -4279,7 +4293,7 @@ public:
~CommandObjectTargetModules()
{
}
-
+
private:
//------------------------------------------------------------------
// For CommandObjectTargetModules only
@@ -4307,12 +4321,12 @@ public:
m_option_group.Append (&m_current_frame_option, LLDB_OPT_SET_2, LLDB_OPT_SET_2);
m_option_group.Finalize();
}
-
+
virtual
~CommandObjectTargetSymbolsAdd ()
{
}
-
+
virtual int
HandleArgumentCompletion (Args &input,
int &cursor_index,
@@ -4325,7 +4339,7 @@ public:
{
std::string completion_str (input.GetArgumentAtIndex(cursor_index));
completion_str.erase (cursor_char_position);
-
+
CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
CommandCompletions::eDiskFileCompletion,
completion_str.c_str(),
@@ -4336,16 +4350,14 @@ public:
matches);
return matches.GetSize();
}
-
+
virtual Options *
GetOptions ()
{
return &m_option_group;
}
-
protected:
-
bool
AddModuleSymbols (Target *target,
ModuleSpec &module_spec,
@@ -4357,7 +4369,7 @@ protected:
{
char symfile_path[PATH_MAX];
symbol_fspec.GetPath (symfile_path, sizeof(symfile_path));
-
+
if (!module_spec.GetUUID().IsValid())
{
if (!module_spec.GetFileSpec() && !module_spec.GetPlatformFileSpec())
@@ -4368,7 +4380,7 @@ protected:
// current target, so we need to find that module in the
// target
ModuleList matching_module_list;
-
+
size_t num_matches = 0;
// First extract all module specs from the symbol file
lldb_private::ModuleSpecList symfile_module_specs;
@@ -4389,7 +4401,7 @@ protected:
num_matches = target->GetImages().FindModules (symfile_uuid_module_spec, matching_module_list);
}
}
-
+
if (num_matches == 0)
{
// No matches yet, iterate through the module specs to find a UUID value that
@@ -4405,7 +4417,7 @@ protected:
ModuleSpec symfile_uuid_module_spec;
symfile_uuid_module_spec.GetUUID() = symfile_module_spec.GetUUID();
num_matches = target->GetImages().FindModules (symfile_uuid_module_spec, matching_module_list);
- }
+ }
}
}
}
@@ -4414,23 +4426,22 @@ protected:
// Just try to match up the file by basename if we have no matches at this point
if (num_matches == 0)
num_matches = target->GetImages().FindModules (module_spec, matching_module_list);
-
+
while (num_matches == 0)
{
ConstString filename_no_extension(module_spec.GetFileSpec().GetFileNameStrippingExtension());
// Empty string returned, lets bail
if (!filename_no_extension)
break;
-
+
// Check if there was no extension to strip and the basename is the same
if (filename_no_extension == module_spec.GetFileSpec().GetFilename())
break;
-
+
// Replace basename with one less extension
module_spec.GetFileSpec().GetFilename() = filename_no_extension;
-
+
num_matches = target->GetImages().FindModules (module_spec, matching_module_list);
-
}
if (num_matches > 1)
@@ -4440,21 +4451,21 @@ protected:
else if (num_matches == 1)
{
ModuleSP module_sp (matching_module_list.GetModuleAtIndex(0));
-
+
// The module has not yet created its symbol vendor, we can just
// give the existing target module the symfile path to use for
// when it decides to create it!
module_sp->SetSymbolFileFileSpec (symbol_fspec);
-
+
SymbolVendor *symbol_vendor = module_sp->GetSymbolVendor(true, &result.GetErrorStream());
if (symbol_vendor)
{
SymbolFile *symbol_file = symbol_vendor->GetSymbolFile();
-
+
if (symbol_file)
{
ObjectFile *object_file = symbol_file->GetObjectFile();
-
+
if (object_file && object_file->GetFileSpec() == symbol_fspec)
{
// Provide feedback that the symfile has been successfully added.
@@ -4462,13 +4473,13 @@ protected:
result.AppendMessageWithFormat("symbol file '%s' has been added to '%s'\n",
symfile_path,
module_fs.GetPath().c_str());
-
+
// Let clients know something changed in the module
// if it is currently loaded
ModuleList module_list;
module_list.Append (module_sp);
target->SymbolsDidLoad (module_list);
-
+
// Make sure we load any scripting resources that may be embedded
// in the debug info files in case the platform supports that.
Error error;
@@ -4674,7 +4685,7 @@ protected:
if (platform_sp->ResolveSymbolFile(*target, module_spec, symfile_spec).Success())
module_spec.GetSymbolFileSpec() = symfile_spec;
}
-
+
ArchSpec arch;
bool symfile_exists = module_spec.GetSymbolFileSpec().Exists();
@@ -4710,13 +4721,11 @@ protected:
}
return result.Succeeded();
}
-
+
OptionGroupOptions m_option_group;
OptionGroupUUID m_uuid_option_group;
OptionGroupFile m_file_option;
OptionGroupBoolean m_current_frame_option;
-
-
};
@@ -4739,13 +4748,13 @@ public:
"target symbols <sub-command> ...")
{
LoadSubCommand ("add", CommandObjectSP (new CommandObjectTargetSymbolsAdd (interpreter)));
-
+
}
virtual
~CommandObjectTargetSymbols()
{
}
-
+
private:
//------------------------------------------------------------------
// For CommandObjectTargetModules only
@@ -4780,9 +4789,9 @@ public:
m_one_liner()
{
}
-
+
~CommandOptions () {}
-
+
const OptionDefinition*
GetDefinitions ()
{
@@ -4802,7 +4811,7 @@ public:
m_class_name = option_arg;
m_sym_ctx_specified = true;
break;
-
+
case 'e':
m_line_end = Args::StringToUInt32 (option_arg, UINT_MAX, 0, &success);
if (!success)
@@ -4812,7 +4821,7 @@ public:
}
m_sym_ctx_specified = true;
break;
-
+
case 'l':
m_line_start = Args::StringToUInt32 (option_arg, 0, 0, &success);
if (!success)
@@ -4822,17 +4831,17 @@ public:
}
m_sym_ctx_specified = true;
break;
-
+
case 'i':
m_no_inlines = true;
break;
-
+
case 'n':
m_function_name = option_arg;
m_func_name_type_mask |= eFunctionNameTypeAuto;
m_sym_ctx_specified = true;
break;
-
+
case 'f':
m_file_name = option_arg;
m_sym_ctx_specified = true;
@@ -4890,7 +4899,7 @@ public:
m_thread_index = UINT32_MAX;
m_thread_name.clear();
m_queue_name.clear();
-
+
m_no_inlines = false;
m_sym_ctx_specified = false;
m_thread_specified = false;
@@ -4899,9 +4908,9 @@ public:
m_one_liner.clear();
}
-
+
static OptionDefinition g_option_table[];
-
+
std::string m_class_name;
std::string m_function_name;
uint32_t m_line_start;
@@ -4942,7 +4951,6 @@ public:
}
protected:
-
virtual void
IOHandlerActivated (IOHandler &io_handler)
{
@@ -4953,8 +4961,7 @@ protected:
output_sp->Flush();
}
}
-
-
+
virtual void
IOHandlerInputComplete (IOHandler &io_handler, std::string &line)
{
@@ -4986,12 +4993,12 @@ protected:
}
io_handler.SetIsDone(true);
}
-
+
bool
DoExecute (Args& command, CommandReturnObject &result)
{
m_stop_hook_sp.reset();
-
+
Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
if (target)
{
@@ -5002,63 +5009,63 @@ protected:
if (m_options.m_sym_ctx_specified)
{
specifier_ap.reset(new SymbolContextSpecifier(m_interpreter.GetDebugger().GetSelectedTarget()));
-
+
if (!m_options.m_module_name.empty())
{
specifier_ap->AddSpecification (m_options.m_module_name.c_str(), SymbolContextSpecifier::eModuleSpecified);
}
-
+
if (!m_options.m_class_name.empty())
{
specifier_ap->AddSpecification (m_options.m_class_name.c_str(), SymbolContextSpecifier::eClassOrNamespaceSpecified);
}
-
+
if (!m_options.m_file_name.empty())
{
specifier_ap->AddSpecification (m_options.m_file_name.c_str(), SymbolContextSpecifier::eFileSpecified);
}
-
+
if (m_options.m_line_start != 0)
{
specifier_ap->AddLineSpecification (m_options.m_line_start, SymbolContextSpecifier::eLineStartSpecified);
}
-
+
if (m_options.m_line_end != UINT_MAX)
{
specifier_ap->AddLineSpecification (m_options.m_line_end, SymbolContextSpecifier::eLineEndSpecified);
}
-
+
if (!m_options.m_function_name.empty())
{
specifier_ap->AddSpecification (m_options.m_function_name.c_str(), SymbolContextSpecifier::eFunctionSpecified);
}
}
-
+
if (specifier_ap.get())
new_hook_sp->SetSpecifier (specifier_ap.release());
// Next see if any of the thread options have been entered:
-
+
if (m_options.m_thread_specified)
{
ThreadSpec *thread_spec = new ThreadSpec();
-
+
if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID)
{
thread_spec->SetTID (m_options.m_thread_id);
}
-
+
if (m_options.m_thread_index != UINT32_MAX)
thread_spec->SetIndex (m_options.m_thread_index);
-
+
if (!m_options.m_thread_name.empty())
thread_spec->SetName (m_options.m_thread_name.c_str());
-
+
if (!m_options.m_queue_name.empty())
thread_spec->SetQueueName (m_options.m_queue_name.c_str());
-
+
new_hook_sp->SetThreadSpecifier (thread_spec);
-
+
}
if (m_options.m_use_one_liner)
{
@@ -5082,7 +5089,7 @@ protected:
result.AppendError ("invalid target\n");
result.SetStatus (eReturnStatusFailed);
}
-
+
return result.Succeeded();
}
private:
@@ -5093,29 +5100,29 @@ private:
OptionDefinition
CommandObjectTargetStopHookAdd::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "one-liner", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOneLiner,
+ { LLDB_OPT_SET_ALL, false, "one-liner", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOneLiner,
"Specify a one-line breakpoint command inline. Be sure to surround it with quotes." },
- { LLDB_OPT_SET_ALL, false, "shlib", 's', OptionParser::eRequiredArgument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName,
+ { LLDB_OPT_SET_ALL, false, "shlib", 's', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName,
"Set the module within which the stop-hook is to be run."},
- { LLDB_OPT_SET_ALL, false, "thread-index", 'x', OptionParser::eRequiredArgument, NULL, 0, eArgTypeThreadIndex,
+ { LLDB_OPT_SET_ALL, false, "thread-index", 'x', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadIndex,
"The stop hook is run only for the thread whose index matches this argument."},
- { LLDB_OPT_SET_ALL, false, "thread-id", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeThreadID,
+ { LLDB_OPT_SET_ALL, false, "thread-id", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadID,
"The stop hook is run only for the thread whose TID matches this argument."},
- { LLDB_OPT_SET_ALL, false, "thread-name", 'T', OptionParser::eRequiredArgument, NULL, 0, eArgTypeThreadName,
+ { LLDB_OPT_SET_ALL, false, "thread-name", 'T', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadName,
"The stop hook is run only for the thread whose thread name matches this argument."},
- { LLDB_OPT_SET_ALL, false, "queue-name", 'q', OptionParser::eRequiredArgument, NULL, 0, eArgTypeQueueName,
+ { LLDB_OPT_SET_ALL, false, "queue-name", 'q', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeQueueName,
"The stop hook is run only for threads in the queue whose name is given by this argument."},
- { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
+ { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
"Specify the source file within which the stop-hook is to be run." },
- { LLDB_OPT_SET_1, false, "start-line", 'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeLineNum,
+ { LLDB_OPT_SET_1, false, "start-line", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLineNum,
"Set the start of the line range for which the stop-hook is to be run."},
- { LLDB_OPT_SET_1, false, "end-line", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeLineNum,
+ { LLDB_OPT_SET_1, false, "end-line", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLineNum,
"Set the end of the line range for which the stop-hook is to be run."},
- { LLDB_OPT_SET_2, false, "classname", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeClassName,
+ { LLDB_OPT_SET_2, false, "classname", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeClassName,
"Specify the class within which the stop-hook is to be run." },
- { LLDB_OPT_SET_3, false, "name", 'n', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
+ { LLDB_OPT_SET_3, false, "name", 'n', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
"Set the function name within which the stop hook will be run." },
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#pragma mark CommandObjectTargetStopHookDelete
@@ -5189,7 +5196,7 @@ protected:
result.AppendError ("invalid target\n");
result.SetStatus (eReturnStatusFailed);
}
-
+
return result.Succeeded();
}
};
@@ -5226,7 +5233,7 @@ protected:
// FIXME: see if we can use the breakpoint id style parser?
size_t num_args = command.GetArgumentCount();
bool success;
-
+
if (num_args == 0)
{
target->SetAllStopHooksActiveState (m_enable);
@@ -5297,7 +5304,7 @@ protected:
result.SetStatus (eReturnStatusFailed);
return result.Succeeded();
}
-
+
size_t num_hooks = target->GetNumStopHooks ();
if (num_hooks == 0)
{
@@ -5367,7 +5374,7 @@ CommandObjectMultiwordTarget::CommandObjectMultiwordTarget (CommandInterpreter &
"A set of commands for operating on debugger targets.",
"target <subcommand> [<subcommand-options>]")
{
-
+
LoadSubCommand ("create", CommandObjectSP (new CommandObjectTargetCreate (interpreter)));
LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTargetDelete (interpreter)));
LoadSubCommand ("list", CommandObjectSP (new CommandObjectTargetList (interpreter)));
diff --git a/source/Commands/CommandObjectThread.cpp b/source/Commands/CommandObjectThread.cpp
index 10d661882c92..e7a8652ac898 100644
--- a/source/Commands/CommandObjectThread.cpp
+++ b/source/Commands/CommandObjectThread.cpp
@@ -305,10 +305,10 @@ protected:
OptionDefinition
CommandObjectThreadBacktrace::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount, "How many frames to display (-1 for all)"},
-{ LLDB_OPT_SET_1, false, "start", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFrameIndex, "Frame in which to start the backtrace"},
-{ LLDB_OPT_SET_1, false, "extended", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Show the extended backtrace, if available"},
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCount, "How many frames to display (-1 for all)"},
+{ LLDB_OPT_SET_1, false, "start", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFrameIndex, "Frame in which to start the backtrace"},
+{ LLDB_OPT_SET_1, false, "extended", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "Show the extended backtrace, if available"},
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
enum StepScope
@@ -348,12 +348,37 @@ public:
case 'a':
{
bool success;
- m_avoid_no_debug = Args::StringToBoolean (option_arg, true, &success);
+ bool avoid_no_debug = Args::StringToBoolean (option_arg, true, &success);
if (!success)
error.SetErrorStringWithFormat("invalid boolean value for option '%c'", short_option);
+ else
+ {
+ m_step_in_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
+ }
+ }
+ break;
+
+ case 'A':
+ {
+ bool success;
+ bool avoid_no_debug = Args::StringToBoolean (option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid boolean value for option '%c'", short_option);
+ else
+ {
+ m_step_out_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
+ }
}
break;
+ case 'c':
+ {
+ m_step_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0);
+ if (m_step_count == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg);
+ break;
+ }
+ break;
case 'm':
{
OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
@@ -386,10 +411,12 @@ public:
void
OptionParsingStarting ()
{
- m_avoid_no_debug = true;
+ m_step_in_avoid_no_debug = eLazyBoolCalculate;
+ m_step_out_avoid_no_debug = eLazyBoolCalculate;
m_run_mode = eOnlyDuringStepping;
m_avoid_regexp.clear();
m_step_in_target.clear();
+ m_step_count = 1;
}
const OptionDefinition*
@@ -403,10 +430,12 @@ public:
static OptionDefinition g_option_table[];
// Instance variables to hold the values for command options.
- bool m_avoid_no_debug;
+ LazyBool m_step_in_avoid_no_debug;
+ LazyBool m_step_out_avoid_no_debug;
RunMode m_run_mode;
std::string m_avoid_regexp;
std::string m_step_in_target;
+ int32_t m_step_count;
};
CommandObjectThreadStepWithTypeAndScope (CommandInterpreter &interpreter,
@@ -522,7 +551,9 @@ protected:
frame->GetSymbolContext(eSymbolContextEverything),
m_options.m_step_in_target.c_str(),
stop_other_threads,
- m_options.m_avoid_no_debug);
+ m_options.m_step_in_avoid_no_debug,
+ m_options.m_step_out_avoid_no_debug);
+
if (new_plan_sp && !m_options.m_avoid_regexp.empty())
{
ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (new_plan_sp.get());
@@ -541,7 +572,8 @@ protected:
new_plan_sp = thread->QueueThreadPlanForStepOverRange (abort_other_plans,
frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
frame->GetSymbolContext(eSymbolContextEverything),
- stop_other_threads);
+ stop_other_threads,
+ m_options.m_step_out_avoid_no_debug);
else
new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (true,
abort_other_plans,
@@ -564,7 +596,8 @@ protected:
bool_stop_other_threads,
eVoteYes,
eVoteNoOpinion,
- thread->GetSelectedFrameIndex());
+ thread->GetSelectedFrameIndex(),
+ m_options.m_step_out_avoid_no_debug);
}
else
{
@@ -580,10 +613,22 @@ protected:
{
new_plan_sp->SetIsMasterPlan (true);
new_plan_sp->SetOkayToDiscard (false);
+
+ if (m_options.m_step_count > 1)
+ {
+ if (new_plan_sp->SetIterationCount(m_options.m_step_count))
+ {
+ result.AppendWarning ("step operation does not support iteration count.");
+ }
+ }
process->GetThreadList().SetSelectedThreadByID (thread->GetID());
process->Resume ();
-
+
+ // 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);
if (synchronous_execution)
{
@@ -639,11 +684,13 @@ g_duo_running_mode[] =
OptionDefinition
CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_1, false, "avoid-no-debug", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "A boolean value that sets whether step-in will step over functions with no debug information."},
-{ LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."},
-{ LLDB_OPT_SET_1, false, "step-over-regexp",'r', OptionParser::eRequiredArgument, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."},
-{ LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."},
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_1, false, "step-in-avoids-no-debug", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "A boolean value that sets whether stepping into functions will step over functions with no debug information."},
+{ LLDB_OPT_SET_1, false, "step-out-avoids-no-debug", 'A', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "A boolean value, if true stepping out of functions will continue to step out till it hits a function with debug information."},
+{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst."},
+{ LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, NULL, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."},
+{ LLDB_OPT_SET_1, false, "step-over-regexp",'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."},
+{ LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."},
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -770,8 +817,9 @@ public:
result.AppendMessageWithFormat ("%u, ", thread->GetIndexID());
else
result.AppendMessageWithFormat ("%u ", thread->GetIndexID());
-
- thread->SetResumeState (eStateRunning);
+
+ const bool override_suspend = true;
+ thread->SetResumeState (eStateRunning, override_suspend);
}
else
{
@@ -802,7 +850,8 @@ public:
if (thread == current_thread)
{
result.AppendMessageWithFormat ("Resuming thread 0x%4.4" PRIx64 " in process %" PRIu64 "\n", thread->GetID(), process->GetID());
- thread->SetResumeState (eStateRunning);
+ const bool override_suspend = true;
+ thread->SetResumeState (eStateRunning, override_suspend);
}
else
{
@@ -1177,10 +1226,10 @@ protected:
OptionDefinition
CommandObjectThreadUntil::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_1, false, "frame", 'f', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFrameIndex, "Frame index for until operation - defaults to 0"},
-{ LLDB_OPT_SET_1, false, "thread", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeThreadIndex, "Thread index for the thread for until operation"},
-{ LLDB_OPT_SET_1, false, "run-mode",'m', OptionParser::eRequiredArgument, g_duo_running_mode, 0, eArgTypeRunMode,"Determine how to run other threads while stepping this one"},
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_1, false, "frame", 'f', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFrameIndex, "Frame index for until operation - defaults to 0"},
+{ LLDB_OPT_SET_1, false, "thread", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadIndex, "Thread index for the thread for until operation"},
+{ LLDB_OPT_SET_1, false, "run-mode",'m', OptionParser::eRequiredArgument, NULL, g_duo_running_mode, 0, eArgTypeRunMode,"Determine how to run other threads while stepping this one"},
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -1306,6 +1355,193 @@ protected:
};
//-------------------------------------------------------------------------
+// CommandObjectThreadInfo
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadInfo : public CommandObjectParsed
+{
+public:
+
+ CommandObjectThreadInfo (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "thread info",
+ "Show an extended summary of information about thread(s) in a process.",
+ "thread info",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData thread_idx_arg;
+
+ thread_idx_arg.arg_type = eArgTypeThreadIndex;
+ thread_idx_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (thread_idx_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ OptionParsingStarting ();
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_json = false;
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ const int short_option = m_getopt_table[option_idx].val;
+ Error error;
+
+ switch (short_option)
+ {
+ case 'j':
+ m_json = true;
+ break;
+
+ default:
+ return Error("invalid short option character '%c'", short_option);
+
+ }
+ return error;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ bool m_json;
+
+ static OptionDefinition g_option_table[];
+ };
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+
+ virtual
+ ~CommandObjectThreadInfo ()
+ {
+ }
+
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ Stream &strm = result.GetOutputStream();
+
+ if (command.GetArgumentCount() == 0)
+ {
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+ if (thread->GetDescription (strm, eDescriptionLevelFull, m_options.m_json))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ }
+ else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ uint32_t idx = 0;
+ for (ThreadSP thread_sp : process->Threads())
+ {
+ if (idx != 0)
+ result.AppendMessage("");
+ if (!thread_sp->GetDescription (strm, eDescriptionLevelFull, m_options.m_json))
+ {
+ result.AppendErrorWithFormat ("error displaying info for thread: \"0x%4.4x\"\n", idx);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ ++idx;
+ }
+ }
+ else
+ {
+ const size_t num_args = command.GetArgumentCount();
+ Process *process = m_exe_ctx.GetProcessPtr();
+ Mutex::Locker locker (process->GetThreadList().GetMutex());
+ std::vector<ThreadSP> thread_sps;
+
+ for (size_t i = 0; i < num_args; i++)
+ {
+ bool success;
+
+ uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx));
+
+ if (!thread_sps[i])
+ {
+ result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ }
+
+ for (uint32_t i = 0; i < num_args; i++)
+ {
+ if (!thread_sps[i]->GetDescription (strm, eDescriptionLevelFull, m_options.m_json))
+ {
+ result.AppendErrorWithFormat ("error displaying info for thread: \"%s\"\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (i < num_args - 1)
+ result.AppendMessage("");
+ }
+
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+
+};
+
+OptionDefinition
+CommandObjectThreadInfo::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "json",'j', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display the thread info in JSON format."},
+
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
// CommandObjectThreadReturn
//-------------------------------------------------------------------------
@@ -1477,12 +1713,12 @@ protected:
options.SetUnwindOnError(true);
options.SetUseDynamic(eNoDynamicValues);
- ExecutionResults exe_results = eExecutionSetupError;
+ ExpressionResults exe_results = eExpressionSetupError;
exe_results = target->EvaluateExpression (command,
frame_sp.get(),
return_valobj_sp,
options);
- if (exe_results != eExecutionCompleted)
+ if (exe_results != eExpressionCompleted)
{
if (return_valobj_sp)
result.AppendErrorWithFormat("Error evaluating result expression: %s", return_valobj_sp->GetError().AsCString());
@@ -1515,8 +1751,8 @@ protected:
OptionDefinition
CommandObjectThreadReturn::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_ALL, false, "from-expression", 'x', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Return from the innermost expression evaluation."},
-{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_ALL, false, "from-expression", 'x', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Return from the innermost expression evaluation."},
+{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -1702,23 +1938,23 @@ protected:
OptionDefinition
CommandObjectThreadJump::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
+ { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
"Specifies the source file to jump to."},
- { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeLineNum,
+ { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLineNum,
"Specifies the line number to jump to."},
- { LLDB_OPT_SET_2, true, "by", 'b', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOffset,
+ { LLDB_OPT_SET_2, true, "by", 'b', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOffset,
"Jumps by a relative line offset from the current line."},
- { LLDB_OPT_SET_3, true, "address", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeAddressOrExpression,
+ { LLDB_OPT_SET_3, true, "address", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeAddressOrExpression,
"Jumps to a specific address."},
{ LLDB_OPT_SET_1|
LLDB_OPT_SET_2|
- LLDB_OPT_SET_3, false, "force",'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone,"Allows the PC to leave the current function."},
+ LLDB_OPT_SET_3, false, "force",'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,"Allows the PC to leave the current function."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -1738,6 +1974,7 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter &
LoadSubCommand ("jump", CommandObjectSP (new CommandObjectThreadJump (interpreter)));
LoadSubCommand ("select", CommandObjectSP (new CommandObjectThreadSelect (interpreter)));
LoadSubCommand ("until", CommandObjectSP (new CommandObjectThreadUntil (interpreter)));
+ LoadSubCommand ("info", CommandObjectSP (new CommandObjectThreadInfo (interpreter)));
LoadSubCommand ("step-in", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
interpreter,
"thread step-in",
diff --git a/source/Commands/CommandObjectType.cpp b/source/Commands/CommandObjectType.cpp
index f1b1d2c1900c..640fd6dd3fa4 100644
--- a/source/Commands/CommandObjectType.cpp
+++ b/source/Commands/CommandObjectType.cpp
@@ -17,6 +17,8 @@
// C++ Includes
+#include "llvm/ADT/StringRef.h"
+
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/IOHandler.h"
@@ -98,7 +100,7 @@ public:
static bool
WarnOnPotentialUnquotedUnsignedType (Args& command, CommandReturnObject &result)
{
- for (int idx = 0; idx < command.GetArgumentCount(); idx++)
+ for (unsigned idx = 0; idx < command.GetArgumentCount(); idx++)
{
const char* arg = command.GetArgumentAtIndex(idx);
if (idx+1 < command.GetArgumentCount())
@@ -204,7 +206,7 @@ public:
static const char *g_summary_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n"
"def function (valobj,internal_dict):\n"
" \"\"\"valobj: an SBValue which you want to provide a summary for\n"
- " internal_dict: an LLDB support object not to be used\"\"\"";
+ " internal_dict: an LLDB support object not to be used\"\"\"\n";
StreamFileSP output_sp(io_handler.GetOutputStreamFile());
if (output_sp)
@@ -876,13 +878,13 @@ protected:
OptionDefinition
CommandObjectTypeFormatAdd::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
- { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
- { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
- { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
- { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
- { LLDB_OPT_SET_2, false, "type", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Format variables as if they were of this type."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
+ { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
+ { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
+ { LLDB_OPT_SET_2, false, "type", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Format variables as if they were of this type."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -1054,9 +1056,9 @@ protected:
OptionDefinition
CommandObjectTypeFormatDelete::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "all", 'a', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Delete from every category."},
- { LLDB_OPT_SET_2, false, "category", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Delete from given category."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_1, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Delete from every category."},
+ { LLDB_OPT_SET_2, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Delete from given category."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -1182,8 +1184,8 @@ protected:
OptionDefinition
CommandObjectTypeFormatClear::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "all", 'a', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Clear every category."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Clear every category."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -1395,8 +1397,8 @@ CommandObjectTypeRXFormatList_LoopCallback (
OptionDefinition
CommandObjectTypeFormatList::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "category-regex", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "category-regex", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#ifndef LLDB_DISABLE_PYTHON
@@ -1814,6 +1816,25 @@ CommandObjectTypeSummaryAdd::DoExecute (Args& command, CommandReturnObject &resu
return Execute_StringSummary(command, result);
}
+static bool
+FixArrayTypeNameWithRegex (ConstString &type_name)
+{
+ llvm::StringRef type_name_ref(type_name.GetStringRef());
+
+ if (type_name_ref.endswith("[]"))
+ {
+ std::string type_name_str(type_name.GetCString());
+ type_name_str.resize(type_name_str.length()-2);
+ if (type_name_str.back() != ' ')
+ type_name_str.append(" \\[[0-9]+\\]");
+ else
+ type_name_str.append("\\[[0-9]+\\]");
+ type_name.SetCString(type_name_str.c_str());
+ return true;
+ }
+ return false;
+}
+
bool
CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name,
TypeSummaryImplSP entry,
@@ -1826,17 +1847,8 @@ CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name,
if (type == eRegularSummary)
{
- std::string type_name_str(type_name.GetCString());
- if (type_name_str.compare(type_name_str.length() - 2, 2, "[]") == 0)
- {
- type_name_str.resize(type_name_str.length()-2);
- if (type_name_str.back() != ' ')
- type_name_str.append(" \\[[0-9]+\\]");
- else
- type_name_str.append("\\[[0-9]+\\]");
- type_name.SetCString(type_name_str.c_str());
+ if (FixArrayTypeNameWithRegex (type_name))
type = eRegexSummary;
- }
}
if (type == eRegexSummary)
@@ -1870,21 +1882,21 @@ CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name,
OptionDefinition
CommandObjectTypeSummaryAdd::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
- { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
- { LLDB_OPT_SET_ALL, false, "no-value", 'v', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't show the value, just show the summary, for this type."},
- { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
- { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
- { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
- { LLDB_OPT_SET_1 , true, "inline-children", 'c', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "If true, inline all child values into summary string."},
- { LLDB_OPT_SET_1 , false, "omit-names", 'O', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "If true, omit value names in the summary display."},
- { LLDB_OPT_SET_2 , true, "summary-string", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeSummaryString, "Summary string used to display text and object contents."},
- { LLDB_OPT_SET_3, false, "python-script", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypePythonScript, "Give a one-liner Python script as part of the command."},
- { LLDB_OPT_SET_3, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, 0, eArgTypePythonFunction, "Give the name of a Python function to use for this type."},
- { LLDB_OPT_SET_3, false, "input-python", 'P', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Input Python code to use for this type manually."},
- { LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "expand", 'e', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Expand aggregate data types to show children on separate lines."},
- { LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "name", 'n', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "A name for this summary string."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
+ { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
+ { LLDB_OPT_SET_ALL, false, "no-value", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't show the value, just show the summary, for this type."},
+ { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
+ { LLDB_OPT_SET_1 , true, "inline-children", 'c', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "If true, inline all child values into summary string."},
+ { LLDB_OPT_SET_1 , false, "omit-names", 'O', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "If true, omit value names in the summary display."},
+ { LLDB_OPT_SET_2 , true, "summary-string", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeSummaryString, "Summary string used to display text and object contents."},
+ { LLDB_OPT_SET_3, false, "python-script", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonScript, "Give a one-liner Python script as part of the command."},
+ { LLDB_OPT_SET_3, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction, "Give the name of a Python function to use for this type."},
+ { LLDB_OPT_SET_3, false, "input-python", 'P', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Input Python code to use for this type manually."},
+ { LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "expand", 'e', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Expand aggregate data types to show children on separate lines."},
+ { LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "name", 'n', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "A name for this summary string."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -2049,9 +2061,9 @@ protected:
OptionDefinition
CommandObjectTypeSummaryDelete::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "all", 'a', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Delete from every category."},
- { LLDB_OPT_SET_2, false, "category", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Delete from given category."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_1, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Delete from every category."},
+ { LLDB_OPT_SET_2, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Delete from given category."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
class CommandObjectTypeSummaryClear : public CommandObjectParsed
@@ -2176,8 +2188,8 @@ protected:
OptionDefinition
CommandObjectTypeSummaryClear::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "all", 'a', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Clear every category."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Clear every category."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -2405,8 +2417,8 @@ CommandObjectTypeRXSummaryList_LoopCallback (
OptionDefinition
CommandObjectTypeSummaryList::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "category-regex", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "category-regex", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -2953,8 +2965,8 @@ CommandObjectTypeFilterRXList_LoopCallback (void* pt2self,
OptionDefinition
CommandObjectTypeFilterList::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "category-regex", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "category-regex", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#ifndef LLDB_DISABLE_PYTHON
@@ -3168,8 +3180,8 @@ CommandObjectTypeSynthRXList_LoopCallback (void* pt2self,
OptionDefinition
CommandObjectTypeSynthList::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "category-regex", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "category-regex", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#endif // #ifndef LLDB_DISABLE_PYTHON
@@ -3332,9 +3344,9 @@ protected:
OptionDefinition
CommandObjectTypeFilterDelete::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "all", 'a', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Delete from every category."},
- { LLDB_OPT_SET_2, false, "category", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Delete from given category."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_1, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Delete from every category."},
+ { LLDB_OPT_SET_2, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Delete from given category."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#ifndef LLDB_DISABLE_PYTHON
@@ -3498,9 +3510,9 @@ protected:
OptionDefinition
CommandObjectTypeSynthDelete::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "all", 'a', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Delete from every category."},
- { LLDB_OPT_SET_2, false, "category", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Delete from given category."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_1, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Delete from every category."},
+ { LLDB_OPT_SET_2, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Delete from given category."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#endif // #ifndef LLDB_DISABLE_PYTHON
@@ -3629,8 +3641,8 @@ protected:
OptionDefinition
CommandObjectTypeFilterClear::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "all", 'a', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Clear every category."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Clear every category."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#ifndef LLDB_DISABLE_PYTHON
@@ -3758,8 +3770,8 @@ protected:
OptionDefinition
CommandObjectTypeSynthClear::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "all", 'a', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Clear every category."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Clear every category."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -3897,17 +3909,8 @@ CommandObjectTypeSynthAdd::AddSynth(ConstString type_name,
if (type == eRegularSynth)
{
- std::string type_name_str(type_name.GetCString());
- if (type_name_str.compare(type_name_str.length() - 2, 2, "[]") == 0)
- {
- type_name_str.resize(type_name_str.length()-2);
- if (type_name_str.back() != ' ')
- type_name_str.append(" \\[[0-9]+\\]");
- else
- type_name_str.append("\\[[0-9]+\\]");
- type_name.SetCString(type_name_str.c_str());
- type = eRegularSynth;
- }
+ if (FixArrayTypeNameWithRegex (type_name))
+ type = eRegexSynth;
}
if (category->AnyMatches(type_name,
@@ -3944,14 +3947,14 @@ CommandObjectTypeSynthAdd::AddSynth(ConstString type_name,
OptionDefinition
CommandObjectTypeSynthAdd::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
- { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
- { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
- { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
- { LLDB_OPT_SET_2, false, "python-class", 'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypePythonClass, "Use this Python class to produce synthetic children."},
- { LLDB_OPT_SET_3, false, "input-python", 'P', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Type Python code to generate a class that provides synthetic children."},
- { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
+ { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for references-to-tNULL, ype objects."},
+ { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
+ { LLDB_OPT_SET_2, false, "python-class", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonClass, "Use this Python class to produce synthetic children."},
+ { LLDB_OPT_SET_3, false, "input-python", 'P', OptionParser::eNoArgument,NULL, NULL, 0, eArgTypeNone, "Type Python code to generate a class that NULL, provides synthetic children."},
+ { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
#endif // #ifndef LLDB_DISABLE_PYTHON
@@ -4076,17 +4079,8 @@ private:
if (type == eRegularFilter)
{
- std::string type_name_str(type_name.GetCString());
- if (type_name_str.compare(type_name_str.length() - 2, 2, "[]") == 0)
- {
- type_name_str.resize(type_name_str.length()-2);
- if (type_name_str.back() != ' ')
- type_name_str.append(" \\[[0-9]+\\]");
- else
- type_name_str.append("\\[[0-9]+\\]");
- type_name.SetCString(type_name_str.c_str());
+ if (FixArrayTypeNameWithRegex (type_name))
type = eRegexFilter;
- }
}
if (category->AnyMatches(type_name,
@@ -4250,13 +4244,13 @@ protected:
OptionDefinition
CommandObjectTypeFilterAdd::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
- { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
- { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
- { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
- { LLDB_OPT_SET_ALL, false, "child", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeExpressionPath, "Include this expression path in the synthetic view."},
- { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
+ { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
+ { LLDB_OPT_SET_ALL, false, "child", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeExpressionPath, "Include this expression path in the synthetic view."},
+ { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
class CommandObjectTypeFormat : public CommandObjectMultiword
diff --git a/source/Commands/CommandObjectWatchpoint.cpp b/source/Commands/CommandObjectWatchpoint.cpp
index e55b2ee4d7d8..ca5fe98ccb31 100644
--- a/source/Commands/CommandObjectWatchpoint.cpp
+++ b/source/Commands/CommandObjectWatchpoint.cpp
@@ -28,6 +28,8 @@
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/Target.h"
+#include "llvm/ADT/StringRef.h"
+
#include <vector>
using namespace lldb;
@@ -62,14 +64,6 @@ CheckTargetForWatchpointOperations(Target *target, CommandReturnObject &result)
return true;
}
-// FIXME: This doesn't seem to be the right place for this functionality.
-#include "llvm/ADT/StringRef.h"
-static inline void StripLeadingSpaces(llvm::StringRef &Str)
-{
- while (!Str.empty() && isspace(Str[0]))
- Str = Str.substr(1);
-}
-
// Equivalent class: {"-", "to", "To", "TO"} of range specifier array.
static const char* RSA[4] = { "-", "to", "To", "TO" };
@@ -335,16 +329,16 @@ private:
OptionDefinition
CommandObjectWatchpointList::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "brief", 'b', OptionParser::eNoArgument, NULL, 0, eArgTypeNone,
+ { LLDB_OPT_SET_1, false, "brief", 'b', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
"Give a brief description of the watchpoint (no location info)."},
- { LLDB_OPT_SET_2, false, "full", 'f', OptionParser::eNoArgument, NULL, 0, eArgTypeNone,
+ { LLDB_OPT_SET_2, false, "full", 'f', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
"Give a full description of the watchpoint and its locations."},
- { LLDB_OPT_SET_3, false, "verbose", 'v', OptionParser::eNoArgument, NULL, 0, eArgTypeNone,
+ { LLDB_OPT_SET_3, false, "verbose", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
"Explain everything we know about the watchpoint (for debugging debugger bugs)." },
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -397,7 +391,7 @@ protected:
{
// No watchpoint selected; enable all currently set watchpoints.
target->EnableAllWatchpoints();
- result.AppendMessageWithFormat("All watchpoints enabled. (%zu watchpoints)\n", num_watchpoints);
+ result.AppendMessageWithFormat("All watchpoints enabled. (%" PRIu64 " watchpoints)\n", (uint64_t)num_watchpoints);
result.SetStatus(eReturnStatusSuccessFinishNoResult);
}
else
@@ -476,7 +470,7 @@ protected:
// No watchpoint selected; disable all currently set watchpoints.
if (target->DisableAllWatchpoints())
{
- result.AppendMessageWithFormat("All watchpoints disabled. (%zu watchpoints)\n", num_watchpoints);
+ result.AppendMessageWithFormat("All watchpoints disabled. (%" PRIu64 " watchpoints)\n", (uint64_t)num_watchpoints);
result.SetStatus(eReturnStatusSuccessFinishNoResult);
}
else
@@ -564,7 +558,7 @@ protected:
else
{
target->RemoveAllWatchpoints();
- result.AppendMessageWithFormat("All watchpoints removed. (%zu watchpoints)\n", num_watchpoints);
+ result.AppendMessageWithFormat("All watchpoints removed. (%" PRIu64 " watchpoints)\n", (uint64_t)num_watchpoints);
}
result.SetStatus (eReturnStatusSuccessFinishNoResult);
}
@@ -706,7 +700,7 @@ protected:
if (command.GetArgumentCount() == 0)
{
target->IgnoreAllWatchpoints(m_options.m_ignore_count);
- result.AppendMessageWithFormat("All watchpoints ignored. (%zu watchpoints)\n", num_watchpoints);
+ result.AppendMessageWithFormat("All watchpoints ignored. (%" PRIu64 " watchpoints)\n", (uint64_t)num_watchpoints);
result.SetStatus (eReturnStatusSuccessFinishNoResult);
}
else
@@ -740,8 +734,8 @@ private:
OptionDefinition
CommandObjectWatchpointIgnore::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_ALL, true, "ignore-count", 'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount, "Set the number of times this watchpoint is skipped before stopping." },
- { 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_ALL, true, "ignore-count", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCount, "Set the number of times this watchpoint is skipped before stopping." },
+ { 0, false, NULL, 0 , 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -903,8 +897,8 @@ private:
OptionDefinition
CommandObjectWatchpointModify::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeExpression, "The watchpoint stops only if this condition expression evaluates to true."},
-{ 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
+{ LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeExpression, "The watchpoint stops only if this condition expression evaluates to true."},
+{ 0, false, NULL, 0 , 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
@@ -1099,8 +1093,8 @@ protected:
}
else
{
- result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64 ", size=%zu, variable expression='%s').\n",
- addr, size, command.GetArgumentAtIndex(0));
+ result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64 ", size=%" PRIu64 ", variable expression='%s').\n",
+ addr, (uint64_t)size, command.GetArgumentAtIndex(0));
if (error.AsCString(NULL))
result.AppendError(error.AsCString());
result.SetStatus(eReturnStatusFailed);
@@ -1262,11 +1256,11 @@ protected:
options.SetTryAllThreads(true);
options.SetTimeoutUsec(0);
- ExecutionResults expr_result = target->EvaluateExpression (expr,
+ ExpressionResults expr_result = target->EvaluateExpression (expr,
frame,
valobj_sp,
options);
- if (expr_result != eExecutionCompleted)
+ if (expr_result != eExpressionCompleted)
{
result.GetErrorStream().Printf("error: expression evaluation of address to watch failed\n");
result.GetErrorStream().Printf("expression evaluated: %s\n", expr);
@@ -1308,8 +1302,8 @@ protected:
}
else
{
- result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64 ", size=%zu).\n",
- addr, size);
+ result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64 ", size=%" PRIu64 ").\n",
+ addr, (uint64_t)size);
if (error.AsCString(NULL))
result.AppendError(error.AsCString());
result.SetStatus(eReturnStatusFailed);
diff --git a/source/Commands/CommandObjectWatchpointCommand.cpp b/source/Commands/CommandObjectWatchpointCommand.cpp
index 0083ff140e5a..f46db7a6a82b 100644
--- a/source/Commands/CommandObjectWatchpointCommand.cpp
+++ b/source/Commands/CommandObjectWatchpointCommand.cpp
@@ -519,19 +519,19 @@ g_script_option_enumeration[4] =
OptionDefinition
CommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOneLiner,
+ { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOneLiner,
"Specify a one-line watchpoint command inline. Be sure to surround it with quotes." },
- { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean,
+ { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,
"Specify whether watchpoint command execution should terminate on error." },
- { LLDB_OPT_SET_ALL, false, "script-type", 's', OptionParser::eRequiredArgument, g_script_option_enumeration, 0, eArgTypeNone,
+ { LLDB_OPT_SET_ALL, false, "script-type", 's', OptionParser::eRequiredArgument, NULL, g_script_option_enumeration, 0, eArgTypeNone,
"Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
- { LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, 0, eArgTypePythonFunction,
+ { LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction,
"Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------
diff --git a/source/Core/Address.cpp b/source/Core/Address.cpp
index 5ac2bcce70f0..fa9197d12b70 100644
--- a/source/Core/Address.cpp
+++ b/source/Core/Address.cpp
@@ -427,7 +427,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
break;
case DumpStyleSectionPointerOffset:
- s->Printf("(Section *)%p + ", section_sp.get());
+ s->Printf("(Section *)%p + ", static_cast<void*>(section_sp.get()));
s->Address(m_offset, addr_size);
break;
diff --git a/source/Core/AddressRange.cpp b/source/Core/AddressRange.cpp
index 835a01d82aa4..3505d56b43e2 100644
--- a/source/Core/AddressRange.cpp
+++ b/source/Core/AddressRange.cpp
@@ -196,7 +196,10 @@ AddressRange::Dump(Stream *s, Target *target, Address::DumpStyle style, Address:
void
AddressRange::DumpDebug (Stream *s) const
{
- s->Printf("%p: AddressRange section = %p, offset = 0x%16.16" PRIx64 ", byte_size = 0x%16.16" PRIx64 "\n", this, m_base_addr.GetSection().get(), m_base_addr.GetOffset(), GetByteSize());
+ s->Printf("%p: AddressRange section = %p, offset = 0x%16.16" PRIx64 ", byte_size = 0x%16.16" PRIx64 "\n",
+ static_cast<const void*>(this),
+ static_cast<void*>(m_base_addr.GetSection().get()),
+ m_base_addr.GetOffset(), GetByteSize());
}
//
//bool
diff --git a/source/Core/AddressResolverName.cpp b/source/Core/AddressResolverName.cpp
index dd22e17402ba..9f3b3f506fe0 100644
--- a/source/Core/AddressResolverName.cpp
+++ b/source/Core/AddressResolverName.cpp
@@ -148,7 +148,7 @@ AddressResolverName::SearchCallback
break;
}
- // Remove any duplicates between the funcion list and the symbol list
+ // Remove any duplicates between the function list and the symbol list
if (func_list.GetSize())
{
for (i = 0; i < func_list.GetSize(); i++)
diff --git a/source/Core/ArchSpec.cpp b/source/Core/ArchSpec.cpp
index a93f4bd7b5f7..5f010f066408 100644
--- a/source/Core/ArchSpec.cpp
+++ b/source/Core/ArchSpec.cpp
@@ -14,13 +14,15 @@
#include <string>
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/MachO.h"
+#include "lldb/Utility/SafeMachO.h"
#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/StringList.h"
#include "lldb/Host/Endian.h"
-#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Platform.h"
using namespace lldb;
@@ -41,13 +43,13 @@ namespace lldb_private {
uint32_t max_opcode_byte_size;
llvm::Triple::ArchType machine;
ArchSpec::Core core;
- const char *name;
+ const char * const name;
};
}
// This core information can be looked using the ArchSpec::Core as the index
-static const CoreDefinition g_core_definitions[ArchSpec::kNumCores] =
+static const CoreDefinition g_core_definitions[] =
{
{ eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_generic , "arm" },
{ eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv4 , "armv4" },
@@ -76,6 +78,9 @@ static const CoreDefinition g_core_definitions[ArchSpec::kNumCores] =
{ eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7k , "thumbv7k" },
{ eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7m , "thumbv7m" },
{ eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7em , "thumbv7em" },
+ { eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64, ArchSpec::eCore_arm_arm64 , "arm64" },
+ { 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" },
@@ -102,6 +107,7 @@ static const CoreDefinition g_core_definitions[ArchSpec::kNumCores] =
{ eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i386 , "i386" },
{ eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i486 , "i486" },
{ eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i486sx , "i486sx" },
+ { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i686 , "i686" },
{ eByteOrderLittle, 8, 1, 15, llvm::Triple::x86_64 , ArchSpec::eCore_x86_64_x86_64 , "x86_64" },
{ eByteOrderLittle, 8, 1, 15, llvm::Triple::x86_64 , ArchSpec::eCore_x86_64_x86_64h , "x86_64h" },
@@ -110,9 +116,19 @@ static const CoreDefinition g_core_definitions[ArchSpec::kNumCores] =
{ eByteOrderLittle, 4, 4, 4, llvm::Triple::hexagon , ArchSpec::eCore_hexagon_hexagonv5, "hexagonv5" },
{ eByteOrderLittle, 4, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach32 , "unknown-mach-32" },
- { eByteOrderLittle, 8, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach64 , "unknown-mach-64" }
+ { eByteOrderLittle, 8, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach64 , "unknown-mach-64" },
+
+ { eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba , "kalimba" },
+ { eByteOrderBig , 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba3 , "kalimba3" },
+ { eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba4 , "kalimba4" },
+ { eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba5 , "kalimba5" }
};
+// Ensure that we have an entry in the g_core_definitions for each core. If you comment out an entry above,
+// you will need to comment out the corresponding ArchSpec::Core enumeration.
+static_assert(sizeof(g_core_definitions) / sizeof(CoreDefinition) == ArchSpec::kNumCores, "make sure we have one core definition for each core");
+
+
struct ArchDefinitionEntry
{
ArchSpec::Core core;
@@ -137,7 +153,7 @@ ArchSpec::AutoComplete (const char *name, StringList &matches)
uint32_t i;
if (name && name[0])
{
- for (i = 0; i < ArchSpec::kNumCores; ++i)
+ for (i = 0; i < llvm::array_lengthof(g_core_definitions); ++i)
{
if (NameMatches(g_core_definitions[i].name, eNameMatchStartsWith, name))
matches.AppendString (g_core_definitions[i].name);
@@ -145,7 +161,7 @@ ArchSpec::AutoComplete (const char *name, StringList &matches)
}
else
{
- for (i = 0; i < ArchSpec::kNumCores; ++i)
+ for (i = 0; i < llvm::array_lengthof(g_core_definitions); ++i)
matches.AppendString (g_core_definitions[i].name);
}
return matches.GetSize();
@@ -179,6 +195,10 @@ static const ArchDefinitionEntry g_macho_arch_entries[] =
{ ArchSpec::eCore_arm_armv7k , llvm::MachO::CPU_TYPE_ARM , 12 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_arm_armv7m , llvm::MachO::CPU_TYPE_ARM , 15 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_arm_armv7em , llvm::MachO::CPU_TYPE_ARM , 16 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , CPU_ANY, UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 0 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 1 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 13 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_thumb , llvm::MachO::CPU_TYPE_ARM , 0 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_thumbv4t , llvm::MachO::CPU_TYPE_ARM , 5 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_thumbv5 , llvm::MachO::CPU_TYPE_ARM , 7 , UINT32_MAX , SUBTYPE_MASK },
@@ -221,7 +241,7 @@ static const ArchDefinitionEntry g_macho_arch_entries[] =
};
static const ArchDefinition g_macho_arch_def = {
eArchTypeMachO,
- sizeof(g_macho_arch_entries)/sizeof(g_macho_arch_entries[0]),
+ llvm::array_lengthof(g_macho_arch_entries),
g_macho_arch_entries,
"mach-o"
};
@@ -239,33 +259,39 @@ static const ArchDefinitionEntry g_elf_arch_entries[] =
{ 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_hexagon_generic , llvm::ELF::EM_HEXAGON, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu } // HEXAGON
+ { ArchSpec::eCore_hexagon_generic , llvm::ELF::EM_HEXAGON, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // HEXAGON
+ { ArchSpec::eCore_kalimba , llvm::ELF::EM_CSR_KALIMBA, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA
+ { ArchSpec::eCore_kalimba3 , llvm::ELF::EM_CSR_KALIMBA, 3, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA
+ { ArchSpec::eCore_kalimba4 , llvm::ELF::EM_CSR_KALIMBA, 4, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA
+ { ArchSpec::eCore_kalimba5 , llvm::ELF::EM_CSR_KALIMBA, 5, 0xFFFFFFFFu, 0xFFFFFFFFu } // KALIMBA
+
};
static const ArchDefinition g_elf_arch_def = {
eArchTypeELF,
- sizeof(g_elf_arch_entries)/sizeof(g_elf_arch_entries[0]),
+ llvm::array_lengthof(g_elf_arch_entries),
g_elf_arch_entries,
"elf",
};
static const ArchDefinitionEntry g_coff_arch_entries[] =
{
- { ArchSpec::eCore_x86_32_i386 , llvm::COFF::IMAGE_FILE_MACHINE_I386 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 80386
+ { ArchSpec::eCore_x86_32_i386 , llvm::COFF::IMAGE_FILE_MACHINE_I386 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 80x86
{ ArchSpec::eCore_ppc_generic , llvm::COFF::IMAGE_FILE_MACHINE_POWERPC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC
{ ArchSpec::eCore_ppc_generic , llvm::COFF::IMAGE_FILE_MACHINE_POWERPCFP, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC (with FPU)
{ ArchSpec::eCore_arm_generic , llvm::COFF::IMAGE_FILE_MACHINE_ARM , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM
- { ArchSpec::eCore_arm_armv7 , llvm::COFF::IMAGE_FILE_MACHINE_ARMV7 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARMv7
+ { ArchSpec::eCore_arm_armv7 , llvm::COFF::IMAGE_FILE_MACHINE_ARMNT , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARMv7
{ ArchSpec::eCore_thumb , llvm::COFF::IMAGE_FILE_MACHINE_THUMB , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARMv7
{ ArchSpec::eCore_x86_64_x86_64, llvm::COFF::IMAGE_FILE_MACHINE_AMD64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu } // AMD64
};
static const ArchDefinition g_coff_arch_def = {
eArchTypeCOFF,
- sizeof(g_coff_arch_entries)/sizeof(g_coff_arch_entries[0]),
+ llvm::array_lengthof(g_coff_arch_entries),
g_coff_arch_entries,
"pe-coff",
};
@@ -278,8 +304,7 @@ static const ArchDefinition *g_arch_definitions[] = {
&g_coff_arch_def
};
-static const size_t k_num_arch_definitions =
- sizeof(g_arch_definitions) / sizeof(g_arch_definitions[0]);
+static const size_t k_num_arch_definitions = llvm::array_lengthof(g_arch_definitions);
//===----------------------------------------------------------------------===//
// Static helper functions.
@@ -302,7 +327,7 @@ FindArchDefinition (ArchitectureType arch_type)
static const CoreDefinition *
FindCoreDefinition (llvm::StringRef name)
{
- for (unsigned int i = 0; i < ArchSpec::kNumCores; ++i)
+ for (unsigned int i = 0; i < llvm::array_lengthof(g_core_definitions); ++i)
{
if (name.equals_lower(g_core_definitions[i].name))
return &g_core_definitions[i];
@@ -313,7 +338,7 @@ FindCoreDefinition (llvm::StringRef name)
static inline const CoreDefinition *
FindCoreDefinition (ArchSpec::Core core)
{
- if (core >= 0 && core < ArchSpec::kNumCores)
+ if (core >= 0 && core < llvm::array_lengthof(g_core_definitions))
return &g_core_definitions[core];
return NULL;
}
@@ -472,6 +497,40 @@ ArchSpec::GetMachOCPUSubType () const
return LLDB_INVALID_CPUTYPE;
}
+uint32_t
+ArchSpec::GetDataByteSize () const
+{
+ switch (m_core)
+ {
+ case eCore_kalimba3:
+ return 3;
+ case eCore_kalimba4:
+ return 1;
+ case eCore_kalimba5:
+ return 3;
+ default:
+ return 1;
+ }
+ return 1;
+}
+
+uint32_t
+ArchSpec::GetCodeByteSize () const
+{
+ switch (m_core)
+ {
+ case eCore_kalimba3:
+ return 4;
+ case eCore_kalimba4:
+ return 1;
+ case eCore_kalimba5:
+ return 1;
+ default:
+ return 1;
+ }
+ return 1;
+}
+
llvm::Triple::ArchType
ArchSpec::GetMachine () const
{
@@ -605,11 +664,11 @@ ArchSpec::SetTriple (const char *triple_cstr)
{
// Special case for the current host default architectures...
if (triple_stref.equals (LLDB_ARCH_DEFAULT_32BIT))
- *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture32);
+ *this = HostInfo::GetArchitecture(HostInfo::eArchKind32);
else if (triple_stref.equals (LLDB_ARCH_DEFAULT_64BIT))
- *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture64);
+ *this = HostInfo::GetArchitecture(HostInfo::eArchKind64);
else if (triple_stref.equals (LLDB_ARCH_DEFAULT))
- *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
+ *this = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
}
else
{
@@ -636,11 +695,11 @@ ArchSpec::SetTriple (const char *triple_cstr, Platform *platform)
{
// Special case for the current host default architectures...
if (triple_stref.equals (LLDB_ARCH_DEFAULT_32BIT))
- *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture32);
+ *this = HostInfo::GetArchitecture(HostInfo::eArchKind32);
else if (triple_stref.equals (LLDB_ARCH_DEFAULT_64BIT))
- *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture64);
+ *this = HostInfo::GetArchitecture(HostInfo::eArchKind64);
else if (triple_stref.equals (LLDB_ARCH_DEFAULT))
- *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
+ *this = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
}
else
{
@@ -729,6 +788,7 @@ ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t su
switch (core_def->machine)
{
+ case llvm::Triple::aarch64:
case llvm::Triple::arm:
case llvm::Triple::thumb:
m_triple.setOS (llvm::Triple::IOS);
@@ -736,6 +796,15 @@ ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t su
case llvm::Triple::x86:
case llvm::Triple::x86_64:
+ // Don't set the OS for x86_64 or for x86 as we want to leave it as an "unspecified unknown"
+ // which means if we ask for the OS from the llvm::Triple we get back llvm::Triple::UnknownOS, but
+ // if we ask for the string value for the OS it will come back empty (unspecified).
+ // We do this because we now have iOS and MacOSX as the OS values for x86 and x86_64 for
+ // normal desktop and simulator binaries. And if we compare a "x86_64-apple-ios" to a "x86_64-apple-"
+ // triple, it will say it is compatible (because the OS is unspecified in the second one and will match
+ // anything in the first
+ break;
+
default:
m_triple.setOS (llvm::Triple::MacOSX);
break;
@@ -837,6 +906,7 @@ ArchSpec::IsEqualTo (const ArchSpec& rhs, bool exact_match) const
if (rhs_os_specified && lhs_os_specified)
return false;
}
+
// Only fail if both os types are not unknown
if (lhs_triple_os != llvm::Triple::UnknownOS &&
rhs_triple_os != llvm::Triple::UnknownOS)
@@ -893,6 +963,10 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
case ArchSpec::kCore_any:
return true;
+ case ArchSpec::eCore_arm_generic:
+ if (enforce_exact_match)
+ break;
+ // Fall through to case below
case ArchSpec::kCore_arm_any:
if (core2 >= ArchSpec::kCore_arm_first && core2 <= ArchSpec::kCore_arm_last)
return true;
@@ -901,17 +975,22 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
if (core2 == ArchSpec::kCore_arm_any)
return true;
break;
-
+
case ArchSpec::kCore_x86_32_any:
if ((core2 >= ArchSpec::kCore_x86_32_first && core2 <= ArchSpec::kCore_x86_32_last) || (core2 == ArchSpec::kCore_x86_32_any))
return true;
break;
-
+
+ case ArchSpec::kCore_x86_64_any:
+ if ((core2 >= ArchSpec::kCore_x86_64_first && core2 <= ArchSpec::kCore_x86_64_last) || (core2 == ArchSpec::kCore_x86_64_any))
+ return true;
+ break;
+
case ArchSpec::kCore_ppc_any:
if ((core2 >= ArchSpec::kCore_ppc_first && core2 <= ArchSpec::kCore_ppc_last) || (core2 == ArchSpec::kCore_ppc_any))
return true;
break;
-
+
case ArchSpec::kCore_ppc64_any:
if ((core2 >= ArchSpec::kCore_ppc64_first && core2 <= ArchSpec::kCore_ppc64_last) || (core2 == ArchSpec::kCore_ppc64_any))
return true;
@@ -920,10 +999,13 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
case ArchSpec::eCore_arm_armv6m:
if (!enforce_exact_match)
{
+ if (core2 == ArchSpec::eCore_arm_generic)
+ return true;
try_inverse = false;
if (core2 == ArchSpec::eCore_arm_armv7)
return true;
}
+ break;
case ArchSpec::kCore_hexagon_any:
if ((core2 >= ArchSpec::kCore_hexagon_first && core2 <= ArchSpec::kCore_hexagon_last) || (core2 == ArchSpec::kCore_hexagon_any))
@@ -937,9 +1019,63 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
case ArchSpec::eCore_arm_armv7s:
if (!enforce_exact_match)
{
- try_inverse = false;
+ if (core2 == ArchSpec::eCore_arm_generic)
+ return true;
if (core2 == ArchSpec::eCore_arm_armv7)
return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_x86_64_x86_64h:
+ if (!enforce_exact_match)
+ {
+ try_inverse = false;
+ if (core2 == ArchSpec::eCore_x86_64_x86_64)
+ return true;
+ }
+ break;
+
+ case ArchSpec::eCore_kalimba:
+ case ArchSpec::eCore_kalimba3:
+ case ArchSpec::eCore_kalimba4:
+ case ArchSpec::eCore_kalimba5:
+ if (core2 >= ArchSpec::kCore_kalimba_first && core2 <= ArchSpec::kCore_kalimba_last)
+ {
+ return true;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv8:
+ if (!enforce_exact_match)
+ {
+ if (core2 == ArchSpec::eCore_arm_arm64)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_aarch64)
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_aarch64:
+ if (!enforce_exact_match)
+ {
+ if (core2 == ArchSpec::eCore_arm_arm64)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv8)
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_arm64:
+ if (!enforce_exact_match)
+ {
+ if (core2 == ArchSpec::eCore_arm_aarch64)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv8)
+ return true;
+ try_inverse = false;
}
break;
diff --git a/source/Core/Broadcaster.cpp b/source/Core/Broadcaster.cpp
index 88f39961832f..dc37516c29c2 100644
--- a/source/Core/Broadcaster.cpp
+++ b/source/Core/Broadcaster.cpp
@@ -31,15 +31,16 @@ Broadcaster::Broadcaster (BroadcasterManager *manager, const char *name) :
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Broadcaster::Broadcaster(\"%s\")", this, m_broadcaster_name.AsCString());
-
+ log->Printf ("%p Broadcaster::Broadcaster(\"%s\")",
+ static_cast<void*>(this), m_broadcaster_name.AsCString());
}
Broadcaster::~Broadcaster()
{
Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Broadcaster::~Broadcaster(\"%s\")", this, m_broadcaster_name.AsCString());
+ log->Printf ("%p Broadcaster::~Broadcaster(\"%s\")",
+ static_cast<void*>(this), m_broadcaster_name.AsCString());
Clear();
}
@@ -226,7 +227,7 @@ Broadcaster::PrivateBroadcastEvent (EventSP &event_sp, bool unique)
const uint32_t event_type = event_sp->GetType();
Mutex::Locker event_types_locker(m_listeners_mutex);
-
+
Listener *hijacking_listener = NULL;
if (!m_hijacking_listeners.empty())
{
@@ -242,11 +243,9 @@ Broadcaster::PrivateBroadcastEvent (EventSP &event_sp, bool unique)
StreamString event_description;
event_sp->Dump (&event_description);
log->Printf ("%p Broadcaster(\"%s\")::BroadcastEvent (event_sp = {%s}, unique =%i) hijack = %p",
- this,
- m_broadcaster_name.AsCString(""),
- event_description.GetData(),
- unique,
- hijacking_listener);
+ static_cast<void*>(this), m_broadcaster_name.AsCString(""),
+ event_description.GetData(), unique,
+ static_cast<void*>(hijacking_listener));
}
if (hijacking_listener)
@@ -293,16 +292,12 @@ bool
Broadcaster::HijackBroadcaster (Listener *listener, uint32_t event_mask)
{
Mutex::Locker event_types_locker(m_listeners_mutex);
-
+
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EVENTS));
if (log)
- {
log->Printf ("%p Broadcaster(\"%s\")::HijackBroadcaster (listener(\"%s\")=%p)",
- this,
- m_broadcaster_name.AsCString(""),
- listener->m_name.c_str(),
- listener);
- }
+ static_cast<void*>(this), m_broadcaster_name.AsCString(""),
+ listener->m_name.c_str(), static_cast<void*>(listener));
m_hijacking_listeners.push_back(listener);
m_hijacking_masks.push_back(event_mask);
return true;
@@ -320,10 +315,9 @@ Broadcaster::RestoreBroadcaster ()
{
Listener *listener = m_hijacking_listeners.back();
log->Printf ("%p Broadcaster(\"%s\")::RestoreBroadcaster (about to pop listener(\"%s\")=%p)",
- this,
+ static_cast<void*>(this),
m_broadcaster_name.AsCString(""),
- listener->m_name.c_str(),
- listener);
+ listener->m_name.c_str(), static_cast<void*>(listener));
}
m_hijacking_listeners.pop_back();
}
diff --git a/source/Core/Communication.cpp b/source/Core/Communication.cpp
index f05ce320b5be..d71c9881a6f3 100644
--- a/source/Core/Communication.cpp
+++ b/source/Core/Communication.cpp
@@ -380,11 +380,24 @@ Communication::ReadThread (lldb::thread_arg_t p)
if (comm->GetCloseOnEOF())
done = true;
break;
+ case eConnectionStatusError: // Check GetError() for details
+ if (error.GetType() == eErrorTypePOSIX && error.GetError() == EIO)
+ {
+ // EIO on a pipe is usually caused by remote shutdown
+ comm->Disconnect ();
+ done = true;
+ }
+ if (log)
+ error.LogIfError (log,
+ "%p Communication::ReadFromConnection () => status = %s",
+ p,
+ Communication::ConnectionStatusAsCString (status));
+ break;
case eConnectionStatusNoConnection: // No connection
case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
+ case eConnectionStatusInterrupted: // Interrupted
done = true;
// Fall through...
- case eConnectionStatusError: // Check GetError() for details
case eConnectionStatusTimedOut: // Request timed out
if (log)
error.LogIfError (log,
@@ -433,6 +446,7 @@ Communication::ConnectionStatusAsCString (lldb::ConnectionStatus status)
case eConnectionStatusNoConnection: return "no connection";
case eConnectionStatusLostConnection: return "lost connection";
case eConnectionStatusEndOfFile: return "end of file";
+ case eConnectionStatusInterrupted: return "interrupted";
}
static char unknown_state_string[64];
diff --git a/source/Core/ConnectionFileDescriptor.cpp b/source/Core/ConnectionFileDescriptor.cpp
index ed876e52c9af..7c8e98a21129 100644
--- a/source/Core/ConnectionFileDescriptor.cpp
+++ b/source/Core/ConnectionFileDescriptor.cpp
@@ -16,7 +16,9 @@
#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Host/Config.h"
+#include "lldb/Host/IOObject.h"
#include "lldb/Host/SocketAddress.h"
+#include "lldb/Host/Socket.h"
// C Includes
#include <errno.h>
@@ -24,20 +26,9 @@
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
+
#ifndef LLDB_DISABLE_POSIX
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/socket.h>
-#include <sys/un.h>
#include <termios.h>
-#include <unistd.h>
-#endif
-#ifdef _WIN32
-#include "lldb/Host/windows/windows.h"
-#include <winsock2.h>
-#include <WS2tcpip.h>
#endif
// C++ Includes
@@ -48,84 +39,44 @@
#endif
// Project includes
#include "lldb/lldb-private-log.h"
-#include "lldb/Interpreter/Args.h"
#include "lldb/Core/Communication.h"
#include "lldb/Core/Log.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/Timer.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/Socket.h"
+#include "lldb/Interpreter/Args.h"
using namespace lldb;
using namespace lldb_private;
-static bool
-DecodeHostAndPort (const char *host_and_port,
- std::string &host_str,
- std::string &port_str,
- int32_t& port,
- Error *error_ptr)
-{
- static RegularExpression g_regex ("([^:]+):([0-9]+)");
- RegularExpression::Match regex_match(2);
- if (g_regex.Execute (host_and_port, &regex_match))
- {
- if (regex_match.GetMatchAtIndex (host_and_port, 1, host_str) &&
- regex_match.GetMatchAtIndex (host_and_port, 2, port_str))
- {
- port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN);
- if (port != INT32_MIN)
- {
- if (error_ptr)
- error_ptr->Clear();
- return true;
- }
- }
- }
- host_str.clear();
- port_str.clear();
- port = INT32_MIN;
- if (error_ptr)
- error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port);
- return false;
-}
-
ConnectionFileDescriptor::ConnectionFileDescriptor () :
Connection(),
- m_fd_send (-1),
- m_fd_recv (-1),
- m_fd_send_type (eFDTypeFile),
- m_fd_recv_type (eFDTypeFile),
- m_udp_send_sockaddr (new SocketAddress()),
- m_socket_timeout_usec(0),
- m_pipe_read(-1),
- m_pipe_write(-1),
+ m_pipe (),
m_mutex (Mutex::eMutexTypeRecursive),
- m_should_close_fd (false),
- m_shutting_down (false)
+ m_shutting_down (false),
+ m_waiting_for_accept (false)
{
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", this);
+ log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()",
+ static_cast<void*>(this));
}
ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) :
Connection(),
- m_fd_send (fd),
- m_fd_recv (fd),
- m_fd_send_type (eFDTypeFile),
- m_fd_recv_type (eFDTypeFile),
- m_udp_send_sockaddr (new SocketAddress()),
- m_socket_timeout_usec(0),
- m_pipe_read(-1),
- m_pipe_write(-1),
+ m_pipe (),
m_mutex (Mutex::eMutexTypeRecursive),
- m_should_close_fd (owns_fd),
- m_shutting_down (false)
+ m_shutting_down (false),
+ m_waiting_for_accept (false)
{
+ m_write_sp.reset(new File(fd, owns_fd));
+ m_read_sp.reset(new File(fd, false));
+
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", this, fd, owns_fd);
+ log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)",
+ static_cast<void*>(this), fd, owns_fd);
OpenCommandPipe ();
}
@@ -134,7 +85,8 @@ ConnectionFileDescriptor::~ConnectionFileDescriptor ()
{
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", this);
+ log->Printf ("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",
+ static_cast<void*>(this));
Disconnect (NULL);
CloseCommandPipe ();
}
@@ -143,31 +95,22 @@ void
ConnectionFileDescriptor::OpenCommandPipe ()
{
CloseCommandPipe();
-
+
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
// Make the command file descriptor here:
- int filedes[2];
-#ifndef LLDB_DISABLE_POSIX
- int result = pipe (filedes);
-#else
- int result = -1;
-#endif
- if (result != 0)
+ if (!m_pipe.Open())
{
if (log)
log->Printf ("%p ConnectionFileDescriptor::OpenCommandPipe () - could not make pipe: %s",
- this,
- strerror(errno));
+ static_cast<void*>(this), strerror(errno));
}
else
{
- m_pipe_read = filedes[0];
- m_pipe_write = filedes[1];
if (log)
log->Printf ("%p ConnectionFileDescriptor::OpenCommandPipe() - success readfd=%d writefd=%d",
- this,
- m_pipe_read,
- m_pipe_write);
+ static_cast<void*>(this),
+ m_pipe.GetReadFileDescriptor(),
+ m_pipe.GetWriteFileDescriptor());
}
}
@@ -177,33 +120,15 @@ ConnectionFileDescriptor::CloseCommandPipe ()
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
if (log)
log->Printf ("%p ConnectionFileDescriptor::CloseCommandPipe()",
- this);
+ static_cast<void*>(this));
- if (m_pipe_read != -1)
- {
-#ifdef _MSC_VER
- llvm_unreachable("pipe close unsupported in MSVC");
-#else
- close (m_pipe_read);
-#endif
- m_pipe_read = -1;
- }
-
- if (m_pipe_write != -1)
- {
-#ifdef _MSC_VER
- llvm_unreachable("pipe close unsupported in MSVC");
-#else
- close (m_pipe_write);
-#endif
- m_pipe_write = -1;
- }
+ m_pipe.Close();
}
bool
ConnectionFileDescriptor::IsConnected () const
{
- return m_fd_send >= 0 || m_fd_recv >= 0;
+ return (m_read_sp && m_read_sp->IsValid()) || (m_write_sp && m_write_sp->IsValid());
}
ConnectionStatus
@@ -212,47 +137,52 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
Mutex::Locker locker (m_mutex);
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
if (log)
- log->Printf ("%p ConnectionFileDescriptor::Connect (url = '%s')", this, s);
+ log->Printf ("%p ConnectionFileDescriptor::Connect (url = '%s')",
+ static_cast<void*>(this), s);
OpenCommandPipe();
-
+
if (s && s[0])
{
- if (strstr(s, "listen://"))
+ if (strstr(s, "listen://") == s)
{
// listen://HOST:PORT
return SocketListen (s + strlen("listen://"), error_ptr);
}
- else if (strstr(s, "accept://"))
+ else if (strstr(s, "accept://") == s)
{
// unix://SOCKNAME
return NamedSocketAccept (s + strlen("accept://"), error_ptr);
}
- else if (strstr(s, "unix-accept://"))
+ else if (strstr(s, "unix-accept://") == s)
{
// unix://SOCKNAME
return NamedSocketAccept (s + strlen("unix-accept://"), error_ptr);
}
- else if (strstr(s, "connect://"))
+ else if (strstr(s, "connect://") == s)
{
return ConnectTCP (s + strlen("connect://"), error_ptr);
}
- else if (strstr(s, "tcp-connect://"))
+ else if (strstr(s, "tcp-connect://") == s)
{
return ConnectTCP (s + strlen("tcp-connect://"), error_ptr);
}
- else if (strstr(s, "udp://"))
+ else if (strstr(s, "udp://") == s)
{
return ConnectUDP (s + strlen("udp://"), error_ptr);
}
- else if (strstr(s, "fd://"))
+#ifndef LLDB_DISABLE_POSIX
+ else if (strstr(s, "fd://") == s)
{
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Protocol is not supported on non-posix hosts '%s'", s);
+ return eConnectionStatusError;
// Just passing a native file descriptor within this current process
// that is already opened (possibly from a service or other source).
s += strlen ("fd://");
bool success = false;
- m_fd_send = m_fd_recv = Args::StringToSInt32 (s, -1, 0, &success);
-
+ int fd = Args::StringToSInt32 (s, -1, 0, &success);
+
if (success)
{
// We have what looks to be a valid file descriptor, but we
@@ -260,26 +190,17 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
// get the flags from the file descriptor and making sure it
// isn't a bad fd.
errno = 0;
-#ifndef LLDB_DISABLE_POSIX
- int flags = ::fcntl (m_fd_send, F_GETFL, 0);
-#else
- int flags = -1;
-#endif
+ int flags = ::fcntl (fd, F_GETFL, 0);
if (flags == -1 || errno == EBADF)
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat ("stale file descriptor: %s", s);
- m_fd_send = m_fd_recv = -1;
+ m_read_sp.reset();
+ m_write_sp.reset();
return eConnectionStatusError;
}
else
{
- // Try and get a socket option from this file descriptor to
- // see if this is a socket and set m_is_socket accordingly.
- int resuse;
- bool is_socket = GetSocketOption (m_fd_send, SOL_SOCKET, SO_REUSEADDR, resuse) == 0;
- if (is_socket)
- m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
// Don't take ownership of a file descriptor that gets passed
// to us since someone else opened the file descriptor and
// handed it to us.
@@ -289,37 +210,55 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
// option be "owns=1" or "owns=0" or something like this to
// allow us to specify this. For now, we assume we must
// assume we don't own it.
- m_should_close_fd = false;
+
+ std::unique_ptr<Socket> tcp_socket;
+ tcp_socket.reset(new Socket(fd, Socket::ProtocolTcp, false));
+ // Try and get a socket option from this file descriptor to
+ // see if this is a socket and set m_is_socket accordingly.
+ int resuse;
+ bool is_socket = !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse);
+ if (is_socket)
+ {
+ m_read_sp = std::move(tcp_socket);
+ m_write_sp = m_read_sp;
+ }
+ else
+ {
+ m_read_sp.reset(new File(fd, false));
+ m_write_sp.reset(new File(fd, false));
+ }
return eConnectionStatusSuccess;
}
}
-
+
if (error_ptr)
error_ptr->SetErrorStringWithFormat ("invalid file descriptor: \"fd://%s\"", s);
- m_fd_send = m_fd_recv = -1;
+ m_read_sp.reset();
+ m_write_sp.reset();
return eConnectionStatusError;
}
- else if (strstr(s, "file://"))
+ else if (strstr(s, "file://") == s)
{
// file:///PATH
const char *path = s + strlen("file://");
-#ifndef LLDB_DISABLE_POSIX
+ int fd = -1;
do
{
- m_fd_send = m_fd_recv = ::open (path, O_RDWR);
- } while (m_fd_send == -1 && errno == EINTR);
- if (m_fd_send == -1)
+ fd = ::open (path, O_RDWR);
+ } while (fd == -1 && errno == EINTR);
+
+ if (fd == -1)
{
if (error_ptr)
error_ptr->SetErrorToErrno();
return eConnectionStatusError;
}
- if (::isatty(m_fd_send))
+ if (::isatty(fd))
{
// Set up serial terminal emulation
struct termios options;
- ::tcgetattr (m_fd_send, &options);
+ ::tcgetattr (fd, &options);
// Set port speed to maximum
::cfsetospeed (&options, B115200);
@@ -332,24 +271,23 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 0;
- ::tcsetattr (m_fd_send, TCSANOW, &options);
+ ::tcsetattr (fd, TCSANOW, &options);
}
- int flags = ::fcntl (m_fd_send, F_GETFL, 0);
+ int flags = ::fcntl (fd, F_GETFL, 0);
if (flags >= 0)
{
if ((flags & O_NONBLOCK) == 0)
{
flags |= O_NONBLOCK;
- ::fcntl (m_fd_send, F_SETFL, flags);
+ ::fcntl (fd, F_SETFL, flags);
}
}
- m_should_close_fd = true;
+ m_read_sp.reset(new File(fd, true));
+ m_write_sp.reset(new File(fd, false));
return eConnectionStatusSuccess;
-#else
- return eConnectionStatusError;
-#endif
}
+#endif
if (error_ptr)
error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s);
return eConnectionStatusError;
@@ -359,81 +297,70 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
return eConnectionStatusError;
}
+bool
+ConnectionFileDescriptor::InterruptRead()
+{
+ return m_pipe.Write("i", 1) == 1;
+}
+
ConnectionStatus
ConnectionFileDescriptor::Disconnect (Error *error_ptr)
{
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
if (log)
- log->Printf ("%p ConnectionFileDescriptor::Disconnect ()", this);
-
- // Reset the port predicate when disconnecting and don't broadcast
- m_port_predicate.SetValue(0, eBroadcastNever);
+ log->Printf ("%p ConnectionFileDescriptor::Disconnect ()",
+ static_cast<void*>(this));
ConnectionStatus status = eConnectionStatusSuccess;
- if (m_fd_send < 0 && m_fd_recv < 0)
+ if (!IsConnected())
{
if (log)
- log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect", this);
+ log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect",
+ static_cast<void*>(this));
return eConnectionStatusSuccess;
}
-
+
+ if (m_read_sp && m_read_sp->IsValid() && m_read_sp->GetFdType() == IOObject::eFDTypeSocket)
+ static_cast<Socket&>(*m_read_sp).PreDisconnect();
+
// Try to get the ConnectionFileDescriptor's mutex. If we fail, that is quite likely
// because somebody is doing a blocking read on our file descriptor. If that's the case,
// then send the "q" char to the command file channel so the read will wake up and the connection
// will then know to shut down.
-
+
m_shutting_down = true;
-
+
Mutex::Locker locker;
- bool got_lock= locker.TryLock (m_mutex);
-
+ bool got_lock = locker.TryLock (m_mutex);
+
if (!got_lock)
{
- if (m_pipe_write != -1 )
+ if (m_pipe.WriteDescriptorIsValid())
{
int result;
- result = write (m_pipe_write, "q", 1);
+ result = m_pipe.Write("q", 1) == 1;
if (log)
- log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, sent 'q' to %d, result = %d.", this, m_pipe_write, result);
+ log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, sent 'q' to %d, result = %d.",
+ static_cast<void*>(this), m_pipe.GetWriteFileDescriptor(), result);
}
else if (log)
- log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, but no command pipe is available.", this);
- locker.Lock (m_mutex);
- }
-
- if (m_should_close_fd == true)
- {
- if (m_fd_send == m_fd_recv)
- {
- status = Close (m_fd_send, m_fd_send_type, error_ptr);
- }
- else
{
- // File descriptors are the different, close both if needed
- if (m_fd_send >= 0)
- status = Close (m_fd_send, m_fd_send_type, error_ptr);
- if (m_fd_recv >= 0)
- {
- ConnectionStatus recv_status = Close (m_fd_recv, m_fd_recv_type, error_ptr);
- if (status == eConnectionStatusSuccess)
- status = recv_status;
- }
+ log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, but no command pipe is available.",
+ static_cast<void*>(this));
}
+ locker.Lock (m_mutex);
}
- // Now set all our descriptors to invalid values.
-
- m_fd_send = m_fd_recv = -1;
+ Error error = m_read_sp->Close();
+ Error error2 = m_write_sp->Close();
+ if (error.Fail() || error2.Fail())
+ status = eConnectionStatusError;
+ if (error_ptr)
+ *error_ptr = error.Fail() ? error : error2;
- if (status != eConnectionStatusSuccess)
- {
-
- return status;
- }
-
m_shutting_down = false;
- return eConnectionStatusSuccess;
+ return status;
}
size_t
@@ -444,9 +371,6 @@ ConnectionFileDescriptor::Read (void *dst,
Error *error_ptr)
{
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %" PRIu64 ")...",
- this, m_fd_recv, dst, (uint64_t)dst_len);
Mutex::Locker locker;
bool got_lock = locker.TryLock (m_mutex);
@@ -454,67 +378,40 @@ ConnectionFileDescriptor::Read (void *dst,
{
if (log)
log->Printf ("%p ConnectionFileDescriptor::Read () failed to get the connection lock.",
- this);
+ static_cast<void*>(this));
if (error_ptr)
error_ptr->SetErrorString ("failed to get the connection lock for read.");
-
+
status = eConnectionStatusTimedOut;
return 0;
}
else if (m_shutting_down)
return eConnectionStatusError;
-
- ssize_t bytes_read = 0;
status = BytesAvailable (timeout_usec, error_ptr);
- if (status == eConnectionStatusSuccess)
- {
- do
- {
-#ifndef LLDB_DISABLE_POSIX
- bytes_read = ::read (m_fd_recv, dst, dst_len);
-#else
- switch (m_fd_send_type) {
- case eFDTypeSocket:
- case eFDTypeSocketUDP:
- bytes_read = ::recv (m_fd_recv, (char*)dst, dst_len, 0);
- break;
- default:
- bytes_read = -1;
- break;
-
- }
-
-#endif
- } while (bytes_read < 0 && errno == EINTR);
- }
-
if (status != eConnectionStatusSuccess)
return 0;
Error error;
+ size_t bytes_read = dst_len;
+ error = m_read_sp->Read(dst, bytes_read);
+
+ if (log)
+ {
+ log->Printf("%p ConnectionFileDescriptor::Read() fd = %" PRIu64 ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s",
+ static_cast<void*>(this),
+ static_cast<uint64_t>(m_read_sp->GetWaitableHandle()),
+ static_cast<void*>(dst),
+ static_cast<uint64_t>(dst_len),
+ static_cast<uint64_t>(bytes_read),
+ error.AsCString());
+ }
+
if (bytes_read == 0)
{
error.Clear(); // End-of-file. Do not automatically close; pass along for the end-of-file handlers.
status = eConnectionStatusEndOfFile;
}
- else if (bytes_read < 0)
- {
- error.SetErrorToErrno();
- }
- else
- {
- error.Clear();
- }
-
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %" PRIu64 ") => %" PRIi64 ", error = %s",
- this,
- m_fd_recv,
- dst,
- (uint64_t)dst_len,
- (int64_t)bytes_read,
- error.AsCString());
if (error_ptr)
*error_ptr = error;
@@ -525,7 +422,7 @@ ConnectionFileDescriptor::Read (void *dst,
switch (error_value)
{
case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read.
- if (m_fd_recv_type == eFDTypeSocket || m_fd_recv_type == eFDTypeSocketUDP)
+ if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket)
status = eConnectionStatusTimedOut;
else
status = eConnectionStatusSuccess;
@@ -562,7 +459,8 @@ ConnectionFileDescriptor::Read (void *dst,
default:
if (log)
- log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s", this, strerror(error_value));
+ log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s",
+ static_cast<void*>(this), strerror(error_value));
status = eConnectionStatusError;
break; // Break to close....
@@ -578,7 +476,9 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat
{
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
if (log)
- log->Printf ("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", this, src, (uint64_t)src_len);
+ log->Printf ("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")",
+ static_cast<void*>(this), static_cast<const void*>(src),
+ static_cast<uint64_t>(src_len));
if (!IsConnected ())
{
@@ -591,78 +491,18 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat
Error error;
- ssize_t bytes_sent = 0;
-
- switch (m_fd_send_type)
- {
-#ifndef LLDB_DISABLE_POSIX
- case eFDTypeFile: // Other FD requireing read/write
- do
- {
- bytes_sent = ::write (m_fd_send, src, src_len);
- } while (bytes_sent < 0 && errno == EINTR);
- break;
-#endif
- case eFDTypeSocket: // Socket requiring send/recv
- do
- {
- bytes_sent = ::send (m_fd_send, (char*)src, src_len, 0);
- } while (bytes_sent < 0 && errno == EINTR);
- break;
-
- case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom
- assert (m_udp_send_sockaddr->GetFamily() != 0);
- do
- {
- bytes_sent = ::sendto (m_fd_send,
- (char*)src,
- src_len,
- 0,
- *m_udp_send_sockaddr,
- m_udp_send_sockaddr->GetLength());
- } while (bytes_sent < 0 && errno == EINTR);
- break;
- }
-
- if (bytes_sent < 0)
- error.SetErrorToErrno ();
- else
- error.Clear ();
+ size_t bytes_sent = src_len;
+ error = m_write_sp->Write(src, bytes_sent);
if (log)
{
- switch (m_fd_send_type)
- {
- case eFDTypeFile: // Other FD requireing read/write
- log->Printf ("%p ConnectionFileDescriptor::Write() ::write (fd = %i, src = %p, src_len = %" PRIu64 ") => %" PRIi64 " (error = %s)",
- this,
- m_fd_send,
- src,
- (uint64_t)src_len,
- (int64_t)bytes_sent,
- error.AsCString());
- break;
-
- case eFDTypeSocket: // Socket requiring send/recv
- log->Printf ("%p ConnectionFileDescriptor::Write() ::send (socket = %i, src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)",
- this,
- m_fd_send,
- src,
- (uint64_t)src_len,
- (int64_t)bytes_sent,
- error.AsCString());
- break;
-
- case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom
- log->Printf ("%p ConnectionFileDescriptor::Write() ::sendto (socket = %i, src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)",
- this,
- m_fd_send,
- src,
- (uint64_t)src_len,
- (int64_t)bytes_sent,
- error.AsCString());
- break;
- }
+ log->Printf ("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)",
+ static_cast<void*>(this),
+ static_cast<uint64_t>(m_write_sp->GetWaitableHandle()),
+ static_cast<const void*>(src),
+ static_cast<uint64_t>(src_len),
+ static_cast<uint64_t>(bytes_sent),
+ error.AsCString());
}
if (error_ptr)
@@ -696,34 +536,43 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat
-#if defined(__APPLE__)
-
// This ConnectionFileDescriptor::BytesAvailable() uses select().
//
// PROS:
// - select is consistent across most unix platforms
-// - this Apple specific version allows for unlimited fds in the fd_sets by
+// - The Apple specific version allows for unlimited fds in the fd_sets by
// setting the _DARWIN_UNLIMITED_SELECT define prior to including the
// required header files.
-
// CONS:
-// - Darwin only
+// - on non-Apple platforms, only supports file descriptors up to FD_SETSIZE.
+// This implementation will assert if it runs into that hard limit to let
+// users know that another ConnectionFileDescriptor::BytesAvailable() should
+// be used or a new version of ConnectionFileDescriptor::BytesAvailable()
+// should be written for the system that is running into the limitations.
+
+#if defined(__APPLE__)
+#define FD_SET_DATA(fds) fds.data()
+#else
+#define FD_SET_DATA(fds) &fds
+#endif
ConnectionStatus
ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
{
// Don't need to take the mutex here separately since we are only called from Read. If we
// ever get used more generally we will need to lock here as well.
-
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_CONNECTION));
if (log)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)",
+ static_cast<void*>(this), timeout_usec);
+
struct timeval *tv_ptr;
struct timeval tv;
if (timeout_usec == UINT32_MAX)
{
- // Infinite wait...
- tv_ptr = NULL;
+ // Inifinite wait...
+ tv_ptr = nullptr;
}
else
{
@@ -733,20 +582,32 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt
tv.tv_usec = time_value.microseconds();
tv_ptr = &tv;
}
-
+
// Make a copy of the file descriptors to make sure we don't
// have another thread change these values out from under us
// and cause problems in the loop below where like in FS_SET()
- const int data_fd = m_fd_recv;
- const int pipe_fd = m_pipe_read;
-
- if (data_fd >= 0)
+ const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle();
+ const int pipe_fd = m_pipe.GetReadFileDescriptor();
+
+ if (handle != IOObject::kInvalidHandleValue)
{
+#if defined(_MSC_VER)
+ // select() won't accept pipes on Windows. The entire Windows codepath needs to be
+ // converted over to using WaitForMultipleObjects and event HANDLEs, but for now at least
+ // this will allow ::select() to not return an error.
+ const bool have_pipe_fd = false;
+#else
const bool have_pipe_fd = pipe_fd >= 0;
-
- while (data_fd == m_fd_recv)
+#if !defined(__APPLE__)
+ assert (handle < FD_SETSIZE);
+ if (have_pipe_fd)
+ assert (pipe_fd < FD_SETSIZE);
+#endif
+#endif
+ while (handle == m_read_sp->GetWaitableHandle())
{
- const int nfds = std::max<int>(data_fd, pipe_fd) + 1;
+ const int nfds = std::max<int>(handle, pipe_fd) + 1;
+#if defined(__APPLE__)
llvm::SmallVector<fd_set, 1> read_fds;
read_fds.resize((nfds/FD_SETSIZE) + 1);
for (size_t i=0; i<read_fds.size(); ++i)
@@ -754,360 +615,62 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt
// FD_SET doesn't bounds check, it just happily walks off the end
// but we have taken care of making the extra storage with our
// SmallVector of fd_set objects
- FD_SET (data_fd, read_fds.data());
- if (have_pipe_fd)
- FD_SET (pipe_fd, read_fds.data());
-
- Error error;
-
- if (log)
- {
- if (have_pipe_fd)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...",
- this, nfds, data_fd, pipe_fd, tv_ptr);
- else
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...",
- this, nfds, data_fd, tv_ptr);
- }
-
- const int num_set_fds = ::select (nfds, read_fds.data(), NULL, NULL, tv_ptr);
- if (num_set_fds < 0)
- error.SetErrorToErrno();
- else
- error.Clear();
-
- if (log)
- {
- if (have_pipe_fd)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) => %d, error = %s",
- this, nfds, data_fd, pipe_fd, tv_ptr, num_set_fds, error.AsCString());
- else
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => %d, error = %s",
- this, nfds, data_fd, tv_ptr, num_set_fds, error.AsCString());
- }
-
- if (error_ptr)
- *error_ptr = error;
-
- if (error.Fail())
- {
- switch (error.GetError())
- {
- case EBADF: // One of the descriptor sets specified an invalid descriptor.
- return eConnectionStatusLostConnection;
-
- case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
- default: // Other unknown error
- return eConnectionStatusError;
-
- case EAGAIN: // The kernel was (perhaps temporarily) unable to
- // allocate the requested number of file descriptors,
- // or we have non-blocking IO
- case EINTR: // A signal was delivered before the time limit
- // expired and before any of the selected events
- // occurred.
- break; // Lets keep reading to until we timeout
- }
- }
- else if (num_set_fds == 0)
- {
- return eConnectionStatusTimedOut;
- }
- else if (num_set_fds > 0)
- {
- // FD_ISSET is happy to deal with a something larger than
- // a single fd_set.
- if (FD_ISSET(data_fd, read_fds.data()))
- return eConnectionStatusSuccess;
- if (have_pipe_fd && FD_ISSET(pipe_fd, read_fds.data()))
- {
- // We got a command to exit. Read the data from that pipe:
- char buffer[16];
- ssize_t bytes_read;
-
- do
- {
- bytes_read = ::read (pipe_fd, buffer, sizeof(buffer));
- } while (bytes_read < 0 && errno == EINTR);
- assert (bytes_read == 1 && buffer[0] == 'q');
-
- if (log)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
- this, (int) bytes_read, buffer);
-
- return eConnectionStatusEndOfFile;
- }
- }
- }
- }
-
- if (error_ptr)
- error_ptr->SetErrorString("not connected");
- return eConnectionStatusLostConnection;
-}
-
#else
-
-// This ConnectionFileDescriptor::BytesAvailable() uses select().
-//
-// PROS:
-// - select is consistent across most unix platforms
-// CONS:
-// - only supports file descriptors up to FD_SETSIZE. This implementation
-// will assert if it runs into that hard limit to let users know that
-// another ConnectionFileDescriptor::BytesAvailable() should be used
-// or a new version of ConnectionFileDescriptor::BytesAvailable() should
-// be written for the system that is running into the limitations. MacOSX
-// uses kqueues, and there is a poll() based implementation below.
-
-ConnectionStatus
-ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
-{
- // Don't need to take the mutex here separately since we are only called from Read. If we
- // ever get used more generally we will need to lock here as well.
-
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
- if (log)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
- struct timeval *tv_ptr;
- struct timeval tv;
- if (timeout_usec == UINT32_MAX)
- {
- // Infinite wait...
- tv_ptr = NULL;
- }
- else
- {
- TimeValue time_value;
- time_value.OffsetWithMicroSeconds (timeout_usec);
- tv.tv_sec = time_value.seconds();
- tv.tv_usec = time_value.microseconds();
- tv_ptr = &tv;
- }
-
- // Make a copy of the file descriptors to make sure we don't
- // have another thread change these values out from under us
- // and cause problems in the loop below where like in FS_SET()
- const int data_fd = m_fd_recv;
- const int pipe_fd = m_pipe_read;
-
- if (data_fd >= 0)
- {
- // If this assert fires off on MacOSX, we will need to switch to using
- // libdispatch to read from file descriptors because poll() is causing
- // kernel panics and if we exceed FD_SETSIZE we will have no choice...
-#ifndef _MSC_VER
- assert (data_fd < FD_SETSIZE);
-#endif
-
- const bool have_pipe_fd = pipe_fd >= 0;
-
- if (have_pipe_fd)
- {
- assert (pipe_fd < FD_SETSIZE);
- }
-
- while (data_fd == m_fd_recv)
- {
fd_set read_fds;
FD_ZERO (&read_fds);
- FD_SET (data_fd, &read_fds);
+#endif
+ FD_SET (handle, FD_SET_DATA(read_fds));
if (have_pipe_fd)
- FD_SET (pipe_fd, &read_fds);
-
- const int nfds = std::max<int>(data_fd, pipe_fd) + 1;
+ FD_SET (pipe_fd, FD_SET_DATA(read_fds));
Error error;
-
+
if (log)
{
if (have_pipe_fd)
log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...",
- this, nfds, data_fd, pipe_fd, tv_ptr);
+ static_cast<void*>(this), nfds, handle, pipe_fd,
+ static_cast<void*>(tv_ptr));
else
log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...",
- this, nfds, data_fd, tv_ptr);
+ static_cast<void*>(this), nfds, handle,
+ static_cast<void*>(tv_ptr));
}
-
- const int num_set_fds = ::select (nfds, &read_fds, NULL, NULL, tv_ptr);
+
+ const int num_set_fds = ::select (nfds, FD_SET_DATA(read_fds), NULL, NULL, tv_ptr);
if (num_set_fds < 0)
error.SetErrorToErrno();
else
error.Clear();
-
+
if (log)
{
if (have_pipe_fd)
log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) => %d, error = %s",
- this, nfds, data_fd, pipe_fd, tv_ptr, num_set_fds, error.AsCString());
+ static_cast<void*>(this), nfds, handle,
+ pipe_fd, static_cast<void*>(tv_ptr), num_set_fds,
+ error.AsCString());
else
log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => %d, error = %s",
- this, nfds, data_fd, tv_ptr, num_set_fds, error.AsCString());
+ static_cast<void*>(this), nfds, handle,
+ static_cast<void*>(tv_ptr), num_set_fds,
+ error.AsCString());
}
if (error_ptr)
*error_ptr = error;
-
- if (error.Fail())
- {
- switch (error.GetError())
- {
- case EBADF: // One of the descriptor sets specified an invalid descriptor.
- return eConnectionStatusLostConnection;
-
- case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
- default: // Other unknown error
- return eConnectionStatusError;
-
- case EAGAIN: // The kernel was (perhaps temporarily) unable to
- // allocate the requested number of file descriptors,
- // or we have non-blocking IO
- case EINTR: // A signal was delivered before the time limit
- // expired and before any of the selected events
- // occurred.
- break; // Lets keep reading to until we timeout
- }
- }
- else if (num_set_fds == 0)
- {
- return eConnectionStatusTimedOut;
- }
- else if (num_set_fds > 0)
- {
- if (FD_ISSET(data_fd, &read_fds))
- return eConnectionStatusSuccess;
- if (have_pipe_fd && FD_ISSET(pipe_fd, &read_fds))
- {
- // We got a command to exit. Read the data from that pipe:
- char buffer[16];
- ssize_t bytes_read;
-
- do
- {
- bytes_read = ::read (pipe_fd, buffer, sizeof(buffer));
- } while (bytes_read < 0 && errno == EINTR);
- assert (bytes_read == 1 && buffer[0] == 'q');
-
- if (log)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
- this, (int) bytes_read, buffer);
-
- return eConnectionStatusEndOfFile;
- }
- }
- }
- }
-
- if (error_ptr)
- error_ptr->SetErrorString("not connected");
- return eConnectionStatusLostConnection;
-}
-
-#endif
-#if 0
-#include <poll.h>
-
-// This ConnectionFileDescriptor::BytesAvailable() uses poll(). poll() should NOT
-// be used on MacOSX as it has all sorts of restrictions on the types of file descriptors
-// that it doesn't support.
-//
-// There may be some systems that properly support poll() that could use this
-// implementation. I will let each system opt into this on their own.
-//
-// PROS:
-// - no restrictions on the fd value that is used
-// CONS:
-// - varies wildly from platform to platform in its implementation restrictions
-
-ConnectionStatus
-ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
-{
- // Don't need to take the mutex here separately since we are only called from Read. If we
- // ever get used more generally we will need to lock here as well.
-
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
- if (log)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
- int timeout_msec = 0;
- if (timeout_usec == UINT32_MAX)
- {
- // Infinite wait...
- timeout_msec = -1;
- }
- else if (timeout_usec == 0)
- {
- // Return immediately, don't wait
- timeout_msec = 0;
- }
- else
- {
- // Convert usec to msec
- timeout_msec = (timeout_usec + 999) / 1000;
- }
-
- // Make a copy of the file descriptors to make sure we don't
- // have another thread change these values out from under us
- // and cause problems in the loop below where like in FS_SET()
- const int data_fd = m_fd_recv;
- const int pipe_fd = m_pipe_read;
-
- // Make sure the file descriptor can be used with select as it
- // must be in range
- if (data_fd >= 0)
- {
- const bool have_pipe_fd = pipe_fd >= 0;
- struct pollfd fds[2] =
- {
- { data_fd, POLLIN, 0 },
- { pipe_fd, POLLIN, 0 }
- };
- const int nfds = have_pipe_fd ? 2 : 1;
- Error error;
- while (data_fd == m_fd_recv)
- {
- const int num_set_fds = ::poll (fds, nfds, timeout_msec);
-
- if (num_set_fds < 0)
- error.SetErrorToErrno();
- else
- error.Clear();
-
- if (error_ptr)
- *error_ptr = error;
-
- if (log)
- {
- if (have_pipe_fd)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::poll (fds={{%i,POLLIN},{%i,POLLIN}}, nfds=%i, timeout_ms=%i) => %d, error = %s\n",
- this,
- data_fd,
- pipe_fd,
- nfds,
- timeout_msec,
- num_set_fds,
- error.AsCString());
- else
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::poll (fds={{%i,POLLIN}}, nfds=%i, timeout_ms=%i) => %d, error = %s\n",
- this,
- data_fd,
- nfds,
- timeout_msec,
- num_set_fds,
- error.AsCString());
- }
-
if (error.Fail())
{
switch (error.GetError())
{
case EBADF: // One of the descriptor sets specified an invalid descriptor.
return eConnectionStatusLostConnection;
-
+
case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
default: // Other unknown error
return eConnectionStatusError;
-
+
case EAGAIN: // The kernel was (perhaps temporarily) unable to
// allocate the requested number of file descriptors,
// or we have non-blocking IO
@@ -1123,595 +686,121 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt
}
else if (num_set_fds > 0)
{
- if (fds[0].revents & POLLIN)
+ if (FD_ISSET(handle, FD_SET_DATA(read_fds)))
return eConnectionStatusSuccess;
- if (fds[1].revents & POLLIN)
+ if (have_pipe_fd && FD_ISSET(pipe_fd, FD_SET_DATA(read_fds)))
{
// We got a command to exit. Read the data from that pipe:
char buffer[16];
ssize_t bytes_read;
-
+
do
{
bytes_read = ::read (pipe_fd, buffer, sizeof(buffer));
} while (bytes_read < 0 && errno == EINTR);
- assert (bytes_read == 1 && buffer[0] == 'q');
- if (log)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
- this, (int) bytes_read, buffer);
-
- return eConnectionStatusEndOfFile;
+ switch (buffer[0])
+ {
+ case 'q':
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
+ static_cast<void*>(this),
+ static_cast<int>(bytes_read), buffer);
+ return eConnectionStatusEndOfFile;
+ case 'i':
+ // Interrupt the current read
+ return eConnectionStatusInterrupted;
+ }
}
}
}
}
+
if (error_ptr)
error_ptr->SetErrorString("not connected");
return eConnectionStatusLostConnection;
}
-#endif
-
-ConnectionStatus
-ConnectionFileDescriptor::Close (int& fd, FDType type, Error *error_ptr)
-{
- if (error_ptr)
- error_ptr->Clear();
- bool success = true;
- // Avoid taking a lock if we can
- if (fd >= 0)
- {
- Mutex::Locker locker (m_mutex);
- // Check the FD after the lock is taken to ensure only one thread
- // can get into the close scope below
- if (fd >= 0)
- {
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::Close (fd = %i)", this,fd);
-#if _WIN32
- if (type != eFDTypeFile)
- success = closesocket(fd) == 0;
- else
-#endif
- success = ::close (fd) == 0;
- // A reference to a FD was passed in, set it to an invalid value
- fd = -1;
- if (!success && error_ptr)
- {
- // Only set the error if we have been asked to since something else
- // might have caused us to try and shut down the connection and may
- // have already set the error.
- error_ptr->SetErrorToErrno();
- }
- }
- }
- if (success)
- return eConnectionStatusSuccess;
- else
- return eConnectionStatusError;
-}
-
ConnectionStatus
ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *error_ptr)
{
-#ifndef LLDB_DISABLE_POSIX
- ConnectionStatus result = eConnectionStatusError;
- struct sockaddr_un saddr_un;
-
- m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
-
- int listen_socket = ::socket (AF_UNIX, SOCK_STREAM, 0);
- if (listen_socket == -1)
- {
- if (error_ptr)
- error_ptr->SetErrorToErrno();
- return eConnectionStatusError;
- }
-
- saddr_un.sun_family = AF_UNIX;
- ::strncpy(saddr_un.sun_path, socket_name, sizeof(saddr_un.sun_path) - 1);
- saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
- saddr_un.sun_len = SUN_LEN (&saddr_un);
-#endif
-
- Host::Unlink (socket_name);
- if (::bind (listen_socket, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0)
- {
- if (::listen (listen_socket, 5) == 0)
- {
- m_fd_send = m_fd_recv = ::accept (listen_socket, NULL, 0);
- if (m_fd_send > 0)
- {
- m_should_close_fd = true;
-
- if (error_ptr)
- error_ptr->Clear();
- result = eConnectionStatusSuccess;
- }
- }
- }
-
- if (result != eConnectionStatusSuccess)
- {
- if (error_ptr)
- error_ptr->SetErrorToErrno();
- }
- // We are done with the listen port
- Close (listen_socket, eFDTypeSocket, NULL);
- return result;
-#else
- return eConnectionStatusError;
-#endif
+ Socket* socket = nullptr;
+ Error error = Socket::UnixDomainAccept(socket_name, socket);
+ if (error_ptr)
+ *error_ptr = error;
+ m_write_sp.reset(socket);
+ m_read_sp = m_write_sp;
+ return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError;
}
ConnectionStatus
ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *error_ptr)
{
-#ifndef LLDB_DISABLE_POSIX
- Disconnect (NULL);
- m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
-
- // Open the socket that was passed in as an option
- struct sockaddr_un saddr_un;
- m_fd_send = m_fd_recv = ::socket (AF_UNIX, SOCK_STREAM, 0);
- if (m_fd_send == -1)
- {
- if (error_ptr)
- error_ptr->SetErrorToErrno();
- return eConnectionStatusError;
- }
-
- saddr_un.sun_family = AF_UNIX;
- ::strncpy(saddr_un.sun_path, socket_name, sizeof(saddr_un.sun_path) - 1);
- saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
- saddr_un.sun_len = SUN_LEN (&saddr_un);
-#endif
-
- if (::connect (m_fd_send, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0)
- {
- if (error_ptr)
- error_ptr->SetErrorToErrno();
- Disconnect (NULL);
- return eConnectionStatusError;
- }
+ Socket* socket = nullptr;
+ Error error = Socket::UnixDomainConnect(socket_name, socket);
if (error_ptr)
- error_ptr->Clear();
- return eConnectionStatusSuccess;
-#else
- return eConnectionStatusError;
-#endif
+ *error_ptr = error;
+ m_write_sp.reset(socket);
+ m_read_sp = m_write_sp;
+ return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError;
}
ConnectionStatus
-ConnectionFileDescriptor::SocketListen (const char *host_and_port, Error *error_ptr)
+ConnectionFileDescriptor::SocketListen(const char *s, Error *error_ptr)
{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::SocketListen (%s)", this, host_and_port);
-
- Disconnect (NULL);
- m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
- std::string host_str;
- std::string port_str;
- int32_t port = INT32_MIN;
- if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr))
- {
- // Might be just a port number
- port = Args::StringToSInt32(host_and_port, -1);
- if (port == -1)
- return eConnectionStatusError;
- else
- host_str.clear();
- }
- const sa_family_t family = AF_INET;
- const int socktype = SOCK_STREAM;
- const int protocol = IPPROTO_TCP;
- int listen_fd = ::socket (family, socktype, protocol);
- if (listen_fd == -1)
- {
- if (error_ptr)
- error_ptr->SetErrorToErrno();
- return eConnectionStatusError;
- }
-
- // enable local address reuse
- SetSocketOption (listen_fd, SOL_SOCKET, SO_REUSEADDR, 1);
-
- SocketAddress listen_addr;
- if (host_str.empty())
- listen_addr.SetToLocalhost(family, port);
- else if (host_str.compare("*") == 0)
- listen_addr.SetToAnyAddress(family, port);
- else
- {
- if (!listen_addr.getaddrinfo(host_str.c_str(), port_str.c_str(), family, socktype, protocol))
- {
- if (error_ptr)
- error_ptr->SetErrorStringWithFormat("unable to resolve hostname '%s'", host_str.c_str());
- Close (listen_fd, eFDTypeSocket, NULL);
- return eConnectionStatusError;
- }
- }
-
- SocketAddress anyaddr;
- if (anyaddr.SetToAnyAddress (family, port))
- {
- int err = ::bind (listen_fd, anyaddr, anyaddr.GetLength());
- if (err == -1)
- {
- if (error_ptr)
- error_ptr->SetErrorToErrno();
- Close (listen_fd, eFDTypeSocket, NULL);
- return eConnectionStatusError;
- }
-
- err = ::listen (listen_fd, 1);
- if (err == -1)
- {
- if (error_ptr)
- error_ptr->SetErrorToErrno();
- Close (listen_fd, eFDTypeSocket, NULL);
- return eConnectionStatusError;
- }
-
- // We were asked to listen on port zero which means we
- // must now read the actual port that was given to us
- // as port zero is a special code for "find an open port
- // for me".
- if (port == 0)
- port = GetSocketPort(listen_fd);
-
- // Set the port predicate since when doing a listen://<host>:<port>
- // it often needs to accept the incoming connection which is a blocking
- // system call. Allowing access to the bound port using a predicate allows
- // us to wait for the port predicate to be set to a non-zero value from
- // another thread in an efficient manor.
- m_port_predicate.SetValue(port, eBroadcastAlways);
-
-
- bool accept_connection = false;
-
- // Loop until we are happy with our connection
- while (!accept_connection)
- {
- struct sockaddr_in accept_addr;
- ::memset (&accept_addr, 0, sizeof accept_addr);
-#if !(defined (__linux__) || defined(_MSC_VER))
- accept_addr.sin_len = sizeof accept_addr;
-#endif
- socklen_t accept_addr_len = sizeof accept_addr;
-
- int fd = ::accept (listen_fd, (struct sockaddr *)&accept_addr, &accept_addr_len);
-
- if (fd == -1)
- {
- if (error_ptr)
- error_ptr->SetErrorToErrno();
- break;
- }
-
- if (listen_addr.sockaddr_in().sin_addr.s_addr == INADDR_ANY)
- {
- accept_connection = true;
- m_fd_send = m_fd_recv = fd;
- }
- else
- {
- if (
-#if !(defined(__linux__) || (defined(_MSC_VER)))
- accept_addr_len == listen_addr.sockaddr_in().sin_len &&
-#endif
- accept_addr.sin_addr.s_addr == listen_addr.sockaddr_in().sin_addr.s_addr)
- {
- accept_connection = true;
- m_fd_send = m_fd_recv = fd;
- }
- else
- {
- ::close (fd);
- m_fd_send = m_fd_recv = -1;
- const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr;
- const uint8_t *listen_ip = (const uint8_t *)&listen_addr.sockaddr_in().sin_addr.s_addr;
- ::fprintf (stderr, "error: rejecting incoming connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)\n",
- accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
- listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
- }
- }
- }
-
- if (m_fd_send == -1)
- {
- Close (listen_fd, eFDTypeSocket, NULL);
- return eConnectionStatusError;
- }
- }
-
- // We are done with the listen port
- Close (listen_fd, eFDTypeSocket, NULL);
-
- m_should_close_fd = true;
+ m_port_predicate.SetValue(0, eBroadcastNever);
- // Keep our TCP packets coming without any delays.
- SetSocketOption (m_fd_send, IPPROTO_TCP, TCP_NODELAY, 1);
+ Socket* socket = nullptr;
+ m_waiting_for_accept = true;
+ Error error = Socket::TcpListen(s, socket, &m_port_predicate);
if (error_ptr)
- error_ptr->Clear();
- return eConnectionStatusSuccess;
-}
-
-ConnectionStatus
-ConnectionFileDescriptor::ConnectTCP (const char *host_and_port, Error *error_ptr)
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::ConnectTCP (host/port = %s)", this, host_and_port);
- Disconnect (NULL);
-
- m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
- std::string host_str;
- std::string port_str;
- int32_t port = INT32_MIN;
- if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr))
- return eConnectionStatusError;
-
- // Create the socket
- m_fd_send = m_fd_recv = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (m_fd_send == -1)
- {
- if (error_ptr)
- error_ptr->SetErrorToErrno();
+ *error_ptr = error;
+ if (error.Fail())
return eConnectionStatusError;
- }
-
- m_should_close_fd = true;
-
- // Enable local address reuse
- SetSocketOption (m_fd_send, SOL_SOCKET, SO_REUSEADDR, 1);
-
- struct sockaddr_in sa;
- ::memset (&sa, 0, sizeof (sa));
- sa.sin_family = AF_INET;
- sa.sin_port = htons (port);
- int inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr);
-
- if (inet_pton_result <= 0)
- {
- struct hostent *host_entry = gethostbyname (host_str.c_str());
- if (host_entry)
- host_str = ::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list);
- inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr);
- if (inet_pton_result <= 0)
- {
-
- if (error_ptr)
- {
- if (inet_pton_result == -1)
- error_ptr->SetErrorToErrno();
- else
- error_ptr->SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str());
- }
- Disconnect (NULL);
-
- return eConnectionStatusError;
- }
- }
-
- if (-1 == ::connect (m_fd_send, (const struct sockaddr *)&sa, sizeof(sa)))
- {
- if (error_ptr)
- error_ptr->SetErrorToErrno();
- Disconnect (NULL);
+ std::unique_ptr<Socket> listening_socket_up;
+ listening_socket_up.reset(socket);
+ socket = nullptr;
+ error = listening_socket_up->BlockingAccept(s, socket);
+ listening_socket_up.reset();
+ if (error_ptr)
+ *error_ptr = error;
+ if (error.Fail())
return eConnectionStatusError;
- }
- // Keep our TCP packets coming without any delays.
- SetSocketOption (m_fd_send, IPPROTO_TCP, TCP_NODELAY, 1);
- if (error_ptr)
- error_ptr->Clear();
- return eConnectionStatusSuccess;
+ m_write_sp.reset(socket);
+ m_read_sp = m_write_sp;
+ return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError;
}
ConnectionStatus
-ConnectionFileDescriptor::ConnectUDP (const char *host_and_port, Error *error_ptr)
+ConnectionFileDescriptor::ConnectTCP(const char *s, Error *error_ptr)
{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::ConnectUDP (host/port = %s)", this, host_and_port);
- Disconnect (NULL);
-
- m_fd_send_type = m_fd_recv_type = eFDTypeSocketUDP;
-
- std::string host_str;
- std::string port_str;
- int32_t port = INT32_MIN;
- if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr))
- return eConnectionStatusError;
-
- // Setup the receiving end of the UDP connection on this localhost
- // on port zero. After we bind to port zero we can read the port.
- m_fd_recv = ::socket (AF_INET, SOCK_DGRAM, 0);
- if (m_fd_recv == -1)
- {
- // Socket creation failed...
- if (error_ptr)
- error_ptr->SetErrorToErrno();
- }
- else
- {
- // Socket was created, now lets bind to the requested port
- SocketAddress addr;
- addr.SetToAnyAddress (AF_INET, 0);
-
- if (::bind (m_fd_recv, addr, addr.GetLength()) == -1)
- {
- // Bind failed...
- if (error_ptr)
- error_ptr->SetErrorToErrno();
- Disconnect (NULL);
- }
- }
-
- if (m_fd_recv == -1)
- return eConnectionStatusError;
-
- // At this point we have setup the recieve port, now we need to
- // setup the UDP send socket
-
- struct addrinfo hints;
- struct addrinfo *service_info_list = NULL;
-
- ::memset (&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_DGRAM;
- int err = ::getaddrinfo (host_str.c_str(), port_str.c_str(), &hints, &service_info_list);
- if (err != 0)
- {
- if (error_ptr)
- error_ptr->SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)",
- host_str.c_str(),
- port_str.c_str(),
- err,
- gai_strerror(err));
- Disconnect (NULL);
- return eConnectionStatusError;
- }
-
- for (struct addrinfo *service_info_ptr = service_info_list;
- service_info_ptr != NULL;
- service_info_ptr = service_info_ptr->ai_next)
- {
- m_fd_send = ::socket (service_info_ptr->ai_family,
- service_info_ptr->ai_socktype,
- service_info_ptr->ai_protocol);
-
- if (m_fd_send != -1)
- {
- *m_udp_send_sockaddr = service_info_ptr;
- break;
- }
- else
- continue;
- }
-
- :: freeaddrinfo (service_info_list);
-
- if (m_fd_send == -1)
- {
- Disconnect (NULL);
- return eConnectionStatusError;
- }
-
+ Socket* socket = nullptr;
+ Error error = Socket::TcpConnect(s, socket);
if (error_ptr)
- error_ptr->Clear();
-
- m_should_close_fd = true;
- return eConnectionStatusSuccess;
-}
-
-#if defined(_WIN32)
-typedef const char * set_socket_option_arg_type;
-typedef char * get_socket_option_arg_type;
-#else // #if defined(_WIN32)
-typedef const void * set_socket_option_arg_type;
-typedef void * get_socket_option_arg_type;
-#endif // #if defined(_WIN32)
-
-int
-ConnectionFileDescriptor::GetSocketOption(int fd, int level, int option_name, int &option_value)
-{
- get_socket_option_arg_type option_value_p = reinterpret_cast<get_socket_option_arg_type>(&option_value);
- socklen_t option_value_size = sizeof(int);
- return ::getsockopt(fd, level, option_name, option_value_p, &option_value_size);
-}
-
-int
-ConnectionFileDescriptor::SetSocketOption(int fd, int level, int option_name, int option_value)
-{
- set_socket_option_arg_type option_value_p = reinterpret_cast<get_socket_option_arg_type>(&option_value);
- return ::setsockopt(fd, level, option_name, option_value_p, sizeof(option_value));
-}
-
-bool
-ConnectionFileDescriptor::SetSocketReceiveTimeout (uint32_t timeout_usec)
-{
- switch (m_fd_recv_type)
- {
- case eFDTypeFile: // Other FD requireing read/write
- break;
-
- case eFDTypeSocket: // Socket requiring send/recv
- case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom
- {
- // Check in case timeout for m_fd has already been set to this value
- if (timeout_usec == m_socket_timeout_usec)
- return true;
- //printf ("ConnectionFileDescriptor::SetSocketReceiveTimeout (timeout_usec = %u)\n", timeout_usec);
-
- struct timeval timeout;
- if (timeout_usec == UINT32_MAX)
- {
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
- }
- else if (timeout_usec == 0)
- {
- // Sending in zero does an infinite timeout, so set this as low
- // as we can go to get an effective zero timeout...
- timeout.tv_sec = 0;
- timeout.tv_usec = 1;
- }
- else
- {
- timeout.tv_sec = timeout_usec / TimeValue::MicroSecPerSec;
- timeout.tv_usec = timeout_usec % TimeValue::MicroSecPerSec;
- }
- if (::setsockopt (m_fd_recv, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<get_socket_option_arg_type>(&timeout), sizeof(timeout)) == 0)
- {
- m_socket_timeout_usec = timeout_usec;
- return true;
- }
- }
- }
- return false;
-}
-
-uint16_t
-ConnectionFileDescriptor::GetSocketPort (int fd)
-{
- // We bound to port zero, so we need to figure out which port we actually bound to
- if (fd >= 0)
- {
- SocketAddress sock_addr;
- socklen_t sock_addr_len = sock_addr.GetMaxLength ();
- if (::getsockname (fd, sock_addr, &sock_addr_len) == 0)
- return sock_addr.GetPort ();
- }
- return 0;
+ *error_ptr = error;
+ m_write_sp.reset(socket);
+ m_read_sp = m_write_sp;
+ return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError;
}
-// If the read file descriptor is a socket, then return
-// the port number that is being used by the socket.
-uint16_t
-ConnectionFileDescriptor::GetReadPort () const
+ConnectionStatus
+ConnectionFileDescriptor::ConnectUDP(const char *s, Error *error_ptr)
{
- return ConnectionFileDescriptor::GetSocketPort (m_fd_recv);
+ Socket* send_socket = nullptr;
+ Socket* recv_socket = nullptr;
+ Error error = Socket::UdpConnect(s, send_socket, recv_socket);
+ if (error_ptr)
+ *error_ptr = error;
+ m_write_sp.reset(send_socket);
+ m_read_sp.reset(recv_socket);
+ return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError;
}
-// If the write file descriptor is a socket, then return
-// the port number that is being used by the socket.
-uint16_t
-ConnectionFileDescriptor::GetWritePort () const
-{
- return ConnectionFileDescriptor::GetSocketPort (m_fd_send);
-}
-uint16_t
-ConnectionFileDescriptor::GetBoundPort (uint32_t timeout_sec)
+uint16_t ConnectionFileDescriptor::GetListeningPort(uint32_t timeout_sec)
{
uint16_t bound_port = 0;
if (timeout_sec == UINT32_MAX)
diff --git a/source/Core/ConnectionMachPort.cpp b/source/Core/ConnectionMachPort.cpp
index 4a090dbe5ec8..05ada9872b5b 100644
--- a/source/Core/ConnectionMachPort.cpp
+++ b/source/Core/ConnectionMachPort.cpp
@@ -127,7 +127,7 @@ ConnectionMachPort::BootstrapCheckIn (const char *port, Error *error_ptr)
{
name_t port_name;
int len = snprintf(port_name, sizeof(port_name), "%s", port);
- if (len < sizeof(port_name))
+ if (static_cast<size_t>(len) < sizeof(port_name))
{
kret = ::bootstrap_check_in (bootstrap_port,
port_name,
@@ -160,7 +160,7 @@ ConnectionMachPort::BootstrapLookup (const char *port,
if (port && port[0])
{
- if (::snprintf (port_name, sizeof (port_name), "%s", port) >= sizeof (port_name))
+ if (static_cast<size_t>(::snprintf (port_name, sizeof (port_name), "%s", port)) >= sizeof (port_name))
{
if (error_ptr)
error_ptr->SetErrorString ("port netname is too long");
diff --git a/source/Core/ConnectionSharedMemory.cpp b/source/Core/ConnectionSharedMemory.cpp
index cd708c4868c9..5db3d687cdb2 100644
--- a/source/Core/ConnectionSharedMemory.cpp
+++ b/source/Core/ConnectionSharedMemory.cpp
@@ -24,6 +24,7 @@
// C++ Includes
// 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"
@@ -125,8 +126,15 @@ ConnectionSharedMemory::Open (bool create, const char *name, size_t size, Error
#ifdef _WIN32
HANDLE handle;
- if (create)
- handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, (DWORD)(size >> 32), (DWORD)(size), name);
+ if (create) {
+ handle = CreateFileMapping(
+ INVALID_HANDLE_VALUE,
+ NULL,
+ PAGE_READWRITE,
+ llvm::Hi_32(size),
+ llvm::Lo_32(size),
+ name);
+ }
else
handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, name);
diff --git a/source/Core/ConstString.cpp b/source/Core/ConstString.cpp
index ce6e51108db5..5657b483a495 100644
--- a/source/Core/ConstString.cpp
+++ b/source/Core/ConstString.cpp
@@ -294,7 +294,10 @@ ConstString::DumpDebug(Stream *s) const
size_t cstr_len = GetLength();
// Only print the parens if we have a non-NULL string
const char *parens = cstr ? "\"" : "";
- s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64, (int)sizeof(void*) * 2, this, parens, cstr, parens, (uint64_t)cstr_len);
+ s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64,
+ static_cast<int>(sizeof(void*) * 2),
+ static_cast<const void*>(this), parens, cstr, parens,
+ static_cast<uint64_t>(cstr_len));
}
void
diff --git a/source/Core/DataBufferHeap.cpp b/source/Core/DataBufferHeap.cpp
index 2c8a865b966c..984b36e54153 100644
--- a/source/Core/DataBufferHeap.cpp
+++ b/source/Core/DataBufferHeap.cpp
@@ -104,6 +104,12 @@ 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);
+}
+
+void
DataBufferHeap::Clear()
{
buffer_t empty;
diff --git a/source/Core/DataBufferMemoryMap.cpp b/source/Core/DataBufferMemoryMap.cpp
index 008b736ef726..4ca43b89eef1 100644
--- a/source/Core/DataBufferMemoryMap.cpp
+++ b/source/Core/DataBufferMemoryMap.cpp
@@ -18,11 +18,13 @@
#include <sys/mman.h>
#endif
+#include "llvm/Support/MathExtras.h"
+
#include "lldb/Core/DataBufferMemoryMap.h"
#include "lldb/Core/Error.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Core/Log.h"
#include "lldb/lldb-private-log.h"
@@ -89,7 +91,7 @@ DataBufferMemoryMap::Clear()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
if (log)
- log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %zu", m_mmap_addr, m_mmap_size);
+ log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %" PRIu64 "", m_mmap_addr, (uint64_t)m_mmap_size);
#ifdef _WIN32
UnmapViewOfFile(m_mmap_addr);
#else
@@ -113,7 +115,7 @@ DataBufferMemoryMap::Clear()
size_t
DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec,
lldb::offset_t offset,
- lldb::offset_t length,
+ size_t length,
bool writeable)
{
if (filespec != NULL)
@@ -124,7 +126,7 @@ DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec,
log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(file=\"%s\", offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i",
filespec->GetPath().c_str(),
offset,
- length,
+ (uint64_t)length,
writeable);
}
char path[PATH_MAX];
@@ -147,16 +149,16 @@ DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec,
Clear();
return 0;
}
-
-
-#ifdef _WIN32
-static size_t win32memmapalignment = 0;
-void LoadWin32MemMapAlignment ()
-{
- SYSTEM_INFO data;
- GetSystemInfo(&data);
- win32memmapalignment = data.dwAllocationGranularity;
-}
+
+
+#ifdef _WIN32
+static size_t win32memmapalignment = 0;
+void LoadWin32MemMapAlignment ()
+{
+ SYSTEM_INFO data;
+ GetSystemInfo(&data);
+ win32memmapalignment = data.dwAllocationGranularity;
+}
#endif
//----------------------------------------------------------------------
@@ -174,7 +176,7 @@ void LoadWin32MemMapAlignment ()
size_t
DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
lldb::offset_t offset,
- lldb::offset_t length,
+ size_t length,
bool writeable,
bool fd_is_file)
{
@@ -184,14 +186,10 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP|LIBLLDB_LOG_VERBOSE));
if (log)
{
-#ifdef _WIN32
- log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(fd=%p, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)",
-#else
- log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(fd=%i, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)",
-#endif
+ log->Printf("DataBufferMemoryMap::MemoryMapFromFileDescriptor(fd=%i, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)",
fd,
offset,
- length,
+ (uint64_t)length,
writeable,
fd_is_file);
}
@@ -199,16 +197,13 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
HANDLE handle = (HANDLE)_get_osfhandle(fd);
DWORD file_size_low, file_size_high;
file_size_low = GetFileSize(handle, &file_size_high);
- const size_t file_size = (file_size_high << 32) | file_size_low;
- const size_t max_bytes_available = file_size - offset;
- if (length == SIZE_MAX)
- {
- length = max_bytes_available;
- }
- else if (length > max_bytes_available)
+ const lldb::offset_t file_size = llvm::Make_64(file_size_high, file_size_low);
+ const lldb::offset_t max_bytes_available = file_size - offset;
+ const size_t max_bytes_mappable = (size_t)std::min<lldb::offset_t>(SIZE_MAX, max_bytes_available);
+ if (length == SIZE_MAX || length > max_bytes_mappable)
{
// Cap the length if too much data was requested
- length = max_bytes_available;
+ length = max_bytes_mappable;
}
if (length > 0)
@@ -216,23 +211,23 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
HANDLE fileMapping = CreateFileMapping(handle, NULL, writeable ? PAGE_READWRITE : PAGE_READONLY, file_size_high, file_size_low, NULL);
if (fileMapping != NULL)
{
- if (win32memmapalignment == 0) LoadWin32MemMapAlignment();
- lldb::offset_t realoffset = offset;
- lldb::offset_t delta = 0;
- if (realoffset % win32memmapalignment != 0) {
- realoffset = realoffset / win32memmapalignment * win32memmapalignment;
- delta = offset - realoffset;
- }
-
- LPVOID data = MapViewOfFile(fileMapping, writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, realoffset, length + delta);
- m_mmap_addr = (uint8_t *)data;
- if (!data) {
- Error error;
- error.SetErrorToErrno ();
+ if (win32memmapalignment == 0) LoadWin32MemMapAlignment();
+ lldb::offset_t realoffset = offset;
+ lldb::offset_t delta = 0;
+ if (realoffset % win32memmapalignment != 0) {
+ realoffset = realoffset / win32memmapalignment * win32memmapalignment;
+ delta = offset - realoffset;
+ }
+
+ LPVOID data = MapViewOfFile(fileMapping, writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, realoffset, length + delta);
+ m_mmap_addr = (uint8_t *)data;
+ if (!data) {
+ Error error;
+ error.SetErrorToErrno ();
} else {
- m_data = m_mmap_addr + delta;
- m_size = length;
- }
+ m_data = m_mmap_addr + delta;
+ m_size = length;
+ }
CloseHandle(fileMapping);
}
}
@@ -240,7 +235,8 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
struct stat stat;
if (::fstat(fd, &stat) == 0)
{
- if (S_ISREG(stat.st_mode) && (stat.st_size > offset))
+ if (S_ISREG(stat.st_mode) &&
+ (stat.st_size > static_cast<off_t>(offset)))
{
const size_t max_bytes_available = stat.st_size - offset;
if (length == SIZE_MAX)
@@ -272,7 +268,7 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
if (error.GetError() == EINVAL)
{
// We may still have a shot at memory mapping if we align things correctly
- size_t page_offset = offset % Host::GetPageSize();
+ size_t page_offset = offset % HostInfo::GetPageSize();
if (page_offset != 0)
{
m_mmap_addr = (uint8_t *)::mmap(NULL, length + page_offset, prot, flags, fd, offset - page_offset);
@@ -311,8 +307,8 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
if (log)
{
- log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %zu, error = %s",
- m_mmap_addr, m_mmap_size, error.AsCString());
+ log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %" PRIu64 ", error = %s",
+ m_mmap_addr, (uint64_t)m_mmap_size, error.AsCString());
}
}
}
diff --git a/source/Core/DataExtractor.cpp b/source/Core/DataExtractor.cpp
index b42c6ff31449..a0958bd6b1c6 100644
--- a/source/Core/DataExtractor.cpp
+++ b/source/Core/DataExtractor.cpp
@@ -52,7 +52,7 @@ ReadInt16(const unsigned char* ptr, offset_t offset)
}
static inline uint32_t
-ReadInt32 (const unsigned char* ptr, offset_t offset)
+ReadInt32 (const unsigned char* ptr, offset_t offset = 0)
{
uint32_t value;
memcpy (&value, ptr + offset, 4);
@@ -60,7 +60,7 @@ ReadInt32 (const unsigned char* ptr, offset_t offset)
}
static inline uint64_t
-ReadInt64(const unsigned char* ptr, offset_t offset)
+ReadInt64(const unsigned char* ptr, offset_t offset = 0)
{
uint64_t value;
memcpy (&value, ptr + offset, 8);
@@ -75,22 +75,6 @@ ReadInt16(const void* ptr)
return value;
}
-static inline uint32_t
-ReadInt32 (const void* ptr)
-{
- uint32_t value;
- memcpy (&value, ptr, 4);
- return value;
-}
-
-static inline uint64_t
-ReadInt64(const void* ptr)
-{
- uint64_t value;
- memcpy (&value, ptr, 8);
- return value;
-}
-
static inline uint16_t
ReadSwapInt16(const unsigned char* ptr, offset_t offset)
{
@@ -409,7 +393,7 @@ DataExtractor::GetU8 (offset_t *offset_ptr) const
//
// RETURNS the non-NULL buffer pointer upon successful extraction of
// all the requested bytes, or NULL when the data is not available in
-// the buffer due to being out of bounds, or unsufficient data.
+// the buffer due to being out of bounds, or insufficient data.
//----------------------------------------------------------------------
void *
DataExtractor::GetU8 (offset_t *offset_ptr, void *dst, uint32_t count) const
@@ -490,7 +474,7 @@ DataExtractor::GetU64_unchecked (offset_t *offset_ptr) const
//
// RETURNS the non-NULL buffer pointer upon successful extraction of
// all the requested bytes, or NULL when the data is not available
-// in the buffer due to being out of bounds, or unsufficient data.
+// in the buffer due to being out of bounds, or insufficient data.
//----------------------------------------------------------------------
void *
DataExtractor::GetU16 (offset_t *offset_ptr, void *void_dst, uint32_t count) const
@@ -553,7 +537,7 @@ DataExtractor::GetU32 (offset_t *offset_ptr) const
//
// RETURNS the non-NULL buffer pointer upon successful extraction of
// all the requested bytes, or NULL when the data is not available
-// in the buffer due to being out of bounds, or unsufficient data.
+// in the buffer due to being out of bounds, or insufficient data.
//----------------------------------------------------------------------
void *
DataExtractor::GetU32 (offset_t *offset_ptr, void *void_dst, uint32_t count) const
@@ -1124,7 +1108,7 @@ DataExtractor::CopyByteOrderedData (offset_t src_offset,
// follows the NULL terminator byte.
//
// If the offset pointed to by "offset_ptr" is out of bounds, or if
-// "length" is non-zero and there aren't enough avaialable
+// "length" is non-zero and there aren't enough available
// bytes, NULL will be returned and "offset_ptr" will not be
// updated.
//----------------------------------------------------------------------
@@ -1150,7 +1134,7 @@ DataExtractor::GetCStr (offset_t *offset_ptr) const
// We reached the end of the data without finding a NULL C string
// terminator. Fall through and return NULL otherwise anyone that
- // would have used the result as a C string can wonder into
+ // would have used the result as a C string can wander into
// unknown memory...
}
return NULL;
@@ -1491,7 +1475,7 @@ DataExtractor::Dump (Stream *s,
if (item_format == eFormatBytesWithASCII && offset > line_start_offset)
{
s->Printf("%*s", static_cast<int>((num_per_line - (offset - line_start_offset)) * 3 + 2), "");
- Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, LLDB_INVALID_OFFSET, LLDB_INVALID_ADDRESS, 0, 0);
+ Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, SIZE_MAX, LLDB_INVALID_ADDRESS, 0, 0);
}
s->EOL();
}
@@ -1516,7 +1500,7 @@ DataExtractor::Dump (Stream *s,
s->Printf ("%s", GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset) ? "true" : "false");
else
{
- s->Printf("error: unsupported byte size (%zu) for boolean format", item_byte_size);
+ s->Printf("error: unsupported byte size (%" PRIu64 ") for boolean format", (uint64_t)item_byte_size);
return offset;
}
break;
@@ -1725,7 +1709,7 @@ DataExtractor::Dump (Stream *s,
}
else
{
- s->Printf("error: unsupported byte size (%zu) for complex integer format", item_byte_size);
+ s->Printf("error: unsupported byte size (%" PRIu64 ") for complex integer format", (uint64_t)item_byte_size);
return offset;
}
}
@@ -1757,7 +1741,7 @@ DataExtractor::Dump (Stream *s,
}
else
{
- s->Printf("error: unsupported byte size (%zu) for complex float format", item_byte_size);
+ s->Printf("error: unsupported byte size (%" PRIu64 ") for complex float format", (uint64_t)item_byte_size);
return offset;
}
break;
@@ -1839,14 +1823,11 @@ DataExtractor::Dump (Stream *s,
else if (item_bit_size == ast->getTypeSize(ast->LongDoubleTy))
{
llvm::APInt apint;
- switch (target_sp->GetArchitecture().GetCore())
+ switch (target_sp->GetArchitecture().GetMachine())
{
- case ArchSpec::eCore_x86_32_i386:
- case ArchSpec::eCore_x86_32_i486:
- case ArchSpec::eCore_x86_32_i486sx:
- case ArchSpec::eCore_x86_64_x86_64:
- case ArchSpec::eCore_x86_64_x86_64h:
- // clang will assert when contructing the apfloat if we use a 16 byte integer value
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ // clang will assert when constructing the apfloat if we use a 16 byte integer value
if (GetAPInt (*this, &offset, 10, apint))
{
llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->LongDoubleTy), apint);
@@ -1909,7 +1890,7 @@ DataExtractor::Dump (Stream *s,
}
else
{
- s->Printf("error: unsupported byte size (%zu) for float format", item_byte_size);
+ s->Printf("error: unsupported byte size (%" PRIu64 ") for float format", (uint64_t)item_byte_size);
return offset;
}
ss.flush();
@@ -1973,7 +1954,7 @@ DataExtractor::Dump (Stream *s,
}
else
{
- s->Printf("error: unsupported byte size (%zu) for hex float format", item_byte_size);
+ s->Printf("error: unsupported byte size (%" PRIu64 ") for hex float format", (uint64_t)item_byte_size);
return offset;
}
break;
@@ -2058,7 +2039,7 @@ DataExtractor::Dump (Stream *s,
if (item_format == eFormatBytesWithASCII && offset > line_start_offset)
{
s->Printf("%*s", static_cast<int>((num_per_line - (offset - line_start_offset)) * 3 + 2), "");
- Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, LLDB_INVALID_OFFSET, LLDB_INVALID_ADDRESS, 0, 0);
+ Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, SIZE_MAX, LLDB_INVALID_ADDRESS, 0, 0);
}
return offset; // Return the offset at which we ended up
}
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp
index 34e0e329f092..178296347677 100644
--- a/source/Core/Debugger.cpp
+++ b/source/Core/Debugger.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
+#include "llvm/ADT/StringRef.h"
#include "lldb/lldb-private.h"
#include "lldb/Core/ConnectionFileDescriptor.h"
@@ -26,12 +27,14 @@
#include "lldb/Core/StreamCallback.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Core/Timer.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/DataFormatters/FormatManager.h"
-#include "lldb/Host/DynamicLibrary.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Terminal.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/OptionValueSInt64.h"
@@ -50,6 +53,8 @@
#include "lldb/Target/Thread.h"
#include "lldb/Utility/AnsiTerminal.h"
+#include "llvm/Support/DynamicLibrary.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -72,7 +77,7 @@ static DebuggerList &
GetDebuggerList()
{
// hide the static debugger list inside a singleton accessor to avoid
- // global init contructors
+ // global init constructors
static DebuggerList g_list;
return g_list;
}
@@ -104,8 +109,11 @@ g_language_enumerators[] =
FILE_AND_LINE\
"{, name = '${thread.name}'}"\
"{, queue = '${thread.queue}'}"\
+ "{, activity = '${thread.info.activity.name}'}" \
+ "{, ${thread.info.trace_messages} messages}" \
"{, stop reason = ${thread.stop-reason}}"\
"{\\nReturn value: ${thread.return-value}}"\
+ "{\\nCompleted expression: ${thread.completed-expression}}"\
"\\n"
#define DEFAULT_FRAME_FORMAT "frame #${frame.index}: ${frame.pc}"\
@@ -406,10 +414,10 @@ Debugger::LoadPlugin (const FileSpec& spec, Error& error)
{
if (g_load_plugin_callback)
{
- lldb::DynamicLibrarySP dynlib_sp = g_load_plugin_callback (shared_from_this(), spec, error);
- if (dynlib_sp)
+ llvm::sys::DynamicLibrary dynlib = g_load_plugin_callback (shared_from_this(), spec, error);
+ if (dynlib.isValid())
{
- m_loaded_plugins.push_back(dynlib_sp);
+ m_loaded_plugins.push_back(dynlib);
return true;
}
}
@@ -470,7 +478,7 @@ LoadPluginCallback
{
// Try and recurse into anything that a directory or symbolic link.
// We must also do this for unknown as sometimes the directory enumeration
- // might be enurating a file system that doesn't have correct file type
+ // might be enumerating a file system that doesn't have correct file type
// information.
return FileSpec::eEnumerateDirectoryResultEnter;
}
@@ -486,7 +494,7 @@ Debugger::InstanceInitialize ()
const bool find_files = true;
const bool find_other = true;
char dir_path[PATH_MAX];
- if (Host::GetLLDBPath (ePathTypeLLDBSystemPlugins, dir_spec))
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBSystemPlugins, dir_spec))
{
if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path)))
{
@@ -498,8 +506,8 @@ Debugger::InstanceInitialize ()
this);
}
}
-
- if (Host::GetLLDBPath (ePathTypeLLDBUserPlugins, dir_spec))
+
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBUserPlugins, dir_spec))
{
if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path)))
{
@@ -629,8 +637,7 @@ Debugger::Debugger (lldb::LogOutputCallback log_callback, void *baton) :
m_instance_name (),
m_loaded_plugins (),
m_event_handler_thread (LLDB_INVALID_HOST_THREAD),
- m_io_handler_thread (LLDB_INVALID_HOST_THREAD),
- m_event_handler_thread_alive(false)
+ m_io_handler_thread (LLDB_INVALID_HOST_THREAD)
{
char instance_cstr[256];
snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID());
@@ -696,6 +703,8 @@ Debugger::Clear()
m_terminal_state.Clear();
if (m_input_file_sp)
m_input_file_sp->GetFile().Close ();
+
+ m_command_interpreter_ap->Clear();
}
bool
@@ -896,9 +905,29 @@ Debugger::RunIOHandler (const IOHandlerSP& reader_sp)
{
Mutex::Locker locker (m_input_reader_stack.GetMutex());
PushIOHandler (reader_sp);
- reader_sp->Activate();
- reader_sp->Run();
- PopIOHandler (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();
+ else
+ break;
+ }
+ }
}
void
@@ -960,13 +989,17 @@ Debugger::PushIOHandler (const IOHandlerSP& reader_sp)
// Got the current top input reader...
IOHandlerSP top_reader_sp (m_input_reader_stack.Top());
- // Push our new input reader
- m_input_reader_stack.Push (reader_sp);
+ // 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);
- // 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();
+ // 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();
+ }
}
bool
@@ -977,7 +1010,7 @@ Debugger::PopIOHandler (const IOHandlerSP& pop_reader_sp)
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 referesh its prompt and if there is one...
+ // 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());
@@ -985,6 +1018,7 @@ Debugger::PopIOHandler (const IOHandlerSP& pop_reader_sp)
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();
@@ -1085,6 +1119,7 @@ Debugger::FindDebuggerWithID (lldb::user_id_t id)
return debugger_sp;
}
+#if 0
static void
TestPromptFormats (StackFrame *frame)
{
@@ -1145,6 +1180,7 @@ TestPromptFormats (StackFrame *frame)
printf ("what we got: %s\n", s.GetData());
}
}
+#endif
static bool
ScanFormatDescriptor (const char* var_name_begin,
@@ -1421,6 +1457,96 @@ IsTokenWithFormat(const char *var_name_begin, const char *var, std::string &form
return false;
}
+// Find information for the "thread.info.*" specifiers in a format string
+static bool
+FormatThreadExtendedInfoRecurse
+(
+ const char *var_name_begin,
+ StructuredData::ObjectSP thread_info_dictionary,
+ const SymbolContext *sc,
+ const ExecutionContext *exe_ctx,
+ Stream &s
+)
+{
+ bool var_success = false;
+ std::string token_format;
+
+ llvm::StringRef var_name(var_name_begin);
+ size_t percent_idx = var_name.find('%');
+ size_t close_curly_idx = var_name.find('}');
+ llvm::StringRef path = var_name;
+ llvm::StringRef formatter = var_name;
+
+ // 'path' will be the dot separated list of objects to transverse up until we hit
+ // a close curly brace, a percent sign, or an end of string.
+ if (percent_idx != llvm::StringRef::npos || close_curly_idx != llvm::StringRef::npos)
+ {
+ if (percent_idx != llvm::StringRef::npos && close_curly_idx != llvm::StringRef::npos)
+ {
+ if (percent_idx < close_curly_idx)
+ {
+ path = var_name.slice(0, percent_idx);
+ formatter = var_name.substr (percent_idx);
+ }
+ else
+ {
+ path = var_name.slice(0, close_curly_idx);
+ formatter = var_name.substr (close_curly_idx);
+ }
+ }
+ else if (percent_idx != llvm::StringRef::npos)
+ {
+ path = var_name.slice(0, percent_idx);
+ formatter = var_name.substr (percent_idx);
+ }
+ else if (close_curly_idx != llvm::StringRef::npos)
+ {
+ path = var_name.slice(0, close_curly_idx);
+ formatter = var_name.substr (close_curly_idx);
+ }
+ }
+
+ StructuredData::ObjectSP value = thread_info_dictionary->GetObjectForDotSeparatedPath (path);
+
+ if (value.get())
+ {
+ if (value->GetType() == StructuredData::Type::eTypeInteger)
+ {
+ if (IsTokenWithFormat (formatter.str().c_str(), "", token_format, "0x%4.4" PRIx64, exe_ctx, sc))
+ {
+ s.Printf(token_format.c_str(), value->GetAsInteger()->GetValue());
+ var_success = true;
+ }
+ }
+ else if (value->GetType() == StructuredData::Type::eTypeFloat)
+ {
+ s.Printf ("%f", value->GetAsFloat()->GetValue());
+ var_success = true;
+ }
+ else if (value->GetType() == StructuredData::Type::eTypeString)
+ {
+ s.Printf("%s", value->GetAsString()->GetValue().c_str());
+ var_success = true;
+ }
+ else if (value->GetType() == StructuredData::Type::eTypeArray)
+ {
+ if (value->GetAsArray()->GetSize() > 0)
+ {
+ s.Printf ("%zu", value->GetAsArray()->GetSize());
+ var_success = true;
+ }
+ }
+ else if (value->GetType() == StructuredData::Type::eTypeDictionary)
+ {
+ s.Printf ("%zu", value->GetAsDictionary()->GetKeys()->GetAsArray()->GetSize());
+ var_success = true;
+ }
+ }
+
+ return var_success;
+}
+
+
static bool
FormatPromptRecurse
(
@@ -1678,6 +1804,13 @@ FormatPromptRecurse
do_deref_pointer = false;
}
+ if (!target)
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] could not calculate target for prompt expression");
+ break;
+ }
+
// we do not want to use the summary for a bitfield of type T:n
// if we were originally dealing with just a T - that would get
// us into an endless recursion
@@ -1945,6 +2078,19 @@ FormatPromptRecurse
}
}
}
+ else if (IsToken (var_name_begin, "completed-expression}"))
+ {
+ StopInfoSP stop_info_sp = thread->GetStopInfo ();
+ if (stop_info_sp && stop_info_sp->IsValid())
+ {
+ ClangExpressionVariableSP expression_var_sp = StopInfo::GetExpressionVariable (stop_info_sp);
+ if (expression_var_sp && expression_var_sp->GetValueObject())
+ {
+ expression_var_sp->GetValueObject()->Dump(s);
+ var_success = true;
+ }
+ }
+ }
else if (IsToken (var_name_begin, "script:"))
{
var_name_begin += ::strlen("script:");
@@ -1953,6 +2099,15 @@ FormatPromptRecurse
if (RunScriptFormatKeyword (s, script_interpreter, thread, script_name))
var_success = true;
}
+ else if (IsToken (var_name_begin, "info."))
+ {
+ var_name_begin += ::strlen("info.");
+ StructuredData::ObjectSP object_sp = thread->GetExtendedInfo();
+ if (object_sp && object_sp->GetType() == StructuredData::Type::eTypeDictionary)
+ {
+ var_success = FormatThreadExtendedInfoRecurse (var_name_begin, object_sp, sc, exe_ctx, s);
+ }
+ }
}
}
}
@@ -2205,7 +2360,29 @@ FormatPromptRecurse
if (args.GetSize() > 0)
{
const char *open_paren = strchr (cstr, '(');
- const char *close_paren = NULL;
+ const char *close_paren = nullptr;
+ const char *generic = strchr(cstr, '<');
+ // if before the arguments list begins there is a template sign
+ // then scan to the end of the generic args before you try to find
+ // the arguments list
+ if (generic && open_paren && generic < open_paren)
+ {
+ int generic_depth = 1;
+ ++generic;
+ for (;
+ *generic && generic_depth > 0;
+ generic++)
+ {
+ if (*generic == '<')
+ generic_depth++;
+ if (*generic == '>')
+ generic_depth--;
+ }
+ if (*generic)
+ open_paren = strchr(generic, '(');
+ else
+ open_paren = nullptr;
+ }
if (open_paren)
{
if (IsToken (open_paren, "(anonymous namespace)"))
@@ -2228,16 +2405,30 @@ FormatPromptRecurse
const size_t num_args = args.GetSize();
for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx)
{
+ std::string buffer;
+
VariableSP var_sp (args.GetVariableAtIndex (arg_idx));
ValueObjectSP var_value_sp (ValueObjectVariable::Create (exe_scope, var_sp));
+ const char *var_representation = nullptr;
const char *var_name = var_value_sp->GetName().GetCString();
- const char *var_value = var_value_sp->GetValueAsCString();
+ if (var_value_sp->GetClangType().IsAggregateType() &&
+ DataVisualization::ShouldPrintAsOneLiner(*var_value_sp.get()))
+ {
+ static StringSummaryFormat format(TypeSummaryImpl::Flags()
+ .SetHideItemNames(false)
+ .SetShowMembersOneLiner(true),
+ "");
+ format.FormatObject(var_value_sp.get(), buffer);
+ var_representation = buffer.c_str();
+ }
+ else
+ var_representation = var_value_sp->GetValueAsCString();
if (arg_idx > 0)
s.PutCString (", ");
if (var_value_sp->GetError().Success())
{
- if (var_value)
- s.Printf ("%s=%s", var_name, var_value);
+ if (var_representation)
+ s.Printf ("%s=%s", var_name, var_representation);
else
s.Printf ("%s=%s at %s", var_name, var_value_sp->GetTypeName().GetCString(), var_value_sp->GetLocationAsCString());
}
@@ -2769,36 +2960,30 @@ 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;
const bool gui_enabled = IsForwardingEvents();
- bool top_io_handler_hid = false;
- if (gui_enabled == false)
- top_io_handler_hid = HideTopIOHandler();
- assert (process_sp);
-
- if (event_type & Process::eBroadcastBitSTDOUT)
+ if (!gui_enabled)
{
- // The process has stdout available, get it and write it out to the
- // appropriate place.
- if (top_io_handler_hid)
- GetProcessSTDOUT (process_sp.get(), NULL);
- }
- else if (event_type & Process::eBroadcastBitSTDERR)
- {
- // The process has stderr available, get it and write it out to the
- // appropriate place.
- if (top_io_handler_hid)
- GetProcessSTDERR (process_sp.get(), NULL);
- }
- else if (event_type & Process::eBroadcastBitStateChanged)
- {
- // Drain all stout and stderr so we don't see any output come after
- // we print our prompts
- if (top_io_handler_hid)
+ bool pop_process_io_handler = false;
+ assert (process_sp);
+
+ if (event_type & Process::eBroadcastBitSTDOUT || event_type & Process::eBroadcastBitStateChanged)
{
- StreamFileSP stream_sp (GetOutputFile());
- GetProcessSTDOUT (process_sp.get(), stream_sp.get());
- GetProcessSTDERR (process_sp.get(), NULL);
+ GetProcessSTDOUT (process_sp.get(), &output_stream);
+ }
+
+ if (event_type & Process::eBroadcastBitSTDERR || event_type & Process::eBroadcastBitStateChanged)
+ {
+ GetProcessSTDERR (process_sp.get(), &error_stream);
+ }
+
+ if (event_type & Process::eBroadcastBitStateChanged)
+ {
+
+ // Drain all stout and stderr so we don't see any output come after
+ // we print our prompts
// Something changed in the process; get the event and report the process's current status and location to
// the user.
StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
@@ -2815,9 +3000,12 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
case eStateStepping:
case eStateDetached:
{
- stream_sp->Printf("Process %" PRIu64 " %s\n",
- process_sp->GetID(),
- StateAsCString (event_state));
+ output_stream.Printf("Process %" PRIu64 " %s\n",
+ process_sp->GetID(),
+ StateAsCString (event_state));
+
+ if (event_state == eStateDetached)
+ pop_process_io_handler = true;
}
break;
@@ -2826,7 +3014,8 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
break;
case eStateExited:
- process_sp->GetStatus(*stream_sp);
+ process_sp->GetStatus(output_stream);
+ pop_process_io_handler = true;
break;
case eStateStopped:
@@ -2842,86 +3031,91 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
if (num_reasons == 1)
{
const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), 0);
- stream_sp->Printf("Process %" PRIu64 " stopped and restarted: %s\n",
- process_sp->GetID(),
- reason ? reason : "<UNKNOWN REASON>");
+ output_stream.Printf("Process %" PRIu64 " stopped and restarted: %s\n",
+ process_sp->GetID(),
+ reason ? reason : "<UNKNOWN REASON>");
}
else
{
- stream_sp->Printf("Process %" PRIu64 " stopped and restarted, reasons:\n",
- process_sp->GetID());
+ output_stream.Printf("Process %" PRIu64 " stopped and restarted, reasons:\n",
+ process_sp->GetID());
for (size_t i = 0; i < num_reasons; i++)
{
const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), i);
- stream_sp->Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>");
+ output_stream.Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>");
}
}
}
}
else
{
- // Lock the thread list so it doesn't change on us
- ThreadList &thread_list = process_sp->GetThreadList();
- Mutex::Locker locker (thread_list.GetMutex());
-
- ThreadSP curr_thread (thread_list.GetSelectedThread());
- ThreadSP thread;
- StopReason curr_thread_stop_reason = eStopReasonInvalid;
- if (curr_thread)
- curr_thread_stop_reason = curr_thread->GetStopReason();
- if (!curr_thread ||
- !curr_thread->IsValid() ||
- curr_thread_stop_reason == eStopReasonInvalid ||
- curr_thread_stop_reason == eStopReasonNone)
+ // Lock the thread list so it doesn't change on us, this is the scope for the locker:
{
- // Prefer a thread that has just completed its plan over another thread as current thread.
- ThreadSP plan_thread;
- ThreadSP other_thread;
- const size_t num_threads = thread_list.GetSize();
- size_t i;
- for (i = 0; i < num_threads; ++i)
+ ThreadList &thread_list = process_sp->GetThreadList();
+ Mutex::Locker locker (thread_list.GetMutex());
+
+ ThreadSP curr_thread (thread_list.GetSelectedThread());
+ ThreadSP thread;
+ StopReason curr_thread_stop_reason = eStopReasonInvalid;
+ if (curr_thread)
+ curr_thread_stop_reason = curr_thread->GetStopReason();
+ if (!curr_thread ||
+ !curr_thread->IsValid() ||
+ curr_thread_stop_reason == eStopReasonInvalid ||
+ curr_thread_stop_reason == eStopReasonNone)
{
- thread = thread_list.GetThreadAtIndex(i);
- StopReason thread_stop_reason = thread->GetStopReason();
- switch (thread_stop_reason)
+ // Prefer a thread that has just completed its plan over another thread as current thread.
+ ThreadSP plan_thread;
+ ThreadSP other_thread;
+ const size_t num_threads = thread_list.GetSize();
+ size_t i;
+ for (i = 0; i < num_threads; ++i)
{
- case eStopReasonInvalid:
- case eStopReasonNone:
- break;
-
- case eStopReasonTrace:
- case eStopReasonBreakpoint:
- case eStopReasonWatchpoint:
- case eStopReasonSignal:
- case eStopReasonException:
- case eStopReasonExec:
- case eStopReasonThreadExiting:
- if (!other_thread)
- other_thread = thread;
- break;
- case eStopReasonPlanComplete:
- if (!plan_thread)
- plan_thread = thread;
- break;
+ thread = thread_list.GetThreadAtIndex(i);
+ StopReason thread_stop_reason = thread->GetStopReason();
+ switch (thread_stop_reason)
+ {
+ case eStopReasonInvalid:
+ case eStopReasonNone:
+ break;
+
+ case eStopReasonTrace:
+ case eStopReasonBreakpoint:
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ case eStopReasonExec:
+ case eStopReasonThreadExiting:
+ if (!other_thread)
+ other_thread = thread;
+ break;
+ case eStopReasonPlanComplete:
+ if (!plan_thread)
+ plan_thread = thread;
+ break;
+ }
}
- }
- if (plan_thread)
- thread_list.SetSelectedThreadByID (plan_thread->GetID());
- else if (other_thread)
- thread_list.SetSelectedThreadByID (other_thread->GetID());
- else
- {
- if (curr_thread && curr_thread->IsValid())
- thread = curr_thread;
+ if (plan_thread)
+ thread_list.SetSelectedThreadByID (plan_thread->GetID());
+ else if (other_thread)
+ thread_list.SetSelectedThreadByID (other_thread->GetID());
else
- thread = thread_list.GetThreadAtIndex(0);
-
- if (thread)
- thread_list.SetSelectedThreadByID (thread->GetID());
+ {
+ if (curr_thread && curr_thread->IsValid())
+ thread = curr_thread;
+ else
+ thread = thread_list.GetThreadAtIndex(0);
+
+ if (thread)
+ thread_list.SetSelectedThreadByID (thread->GetID());
+ }
}
}
+ // Drop the ThreadList mutex by here, since GetThreadStatus below might have to run code,
+ // e.g. for Data formatters, and if we hold the ThreadList mutex, then the process is going to
+ // have a hard time restarting the process.
if (GetTargetList().GetSelectedTarget().get() == &process_sp->GetTarget())
{
@@ -2929,8 +3123,8 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
const uint32_t start_frame = 0;
const uint32_t num_frames = 1;
const uint32_t num_frames_with_source = 1;
- process_sp->GetStatus(*stream_sp);
- process_sp->GetThreadStatus (*stream_sp,
+ process_sp->GetStatus(output_stream);
+ process_sp->GetThreadStatus (output_stream,
only_threads_with_stop_reason,
start_frame,
num_frames,
@@ -2940,20 +3134,49 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
{
uint32_t target_idx = GetTargetList().GetIndexOfTarget(process_sp->GetTarget().shared_from_this());
if (target_idx != UINT32_MAX)
- stream_sp->Printf ("Target %d: (", target_idx);
+ output_stream.Printf ("Target %d: (", target_idx);
else
- stream_sp->Printf ("Target <unknown index>: (");
- process_sp->GetTarget().Dump (stream_sp.get(), eDescriptionLevelBrief);
- stream_sp->Printf (") stopped.\n");
+ output_stream.Printf ("Target <unknown index>: (");
+ process_sp->GetTarget().Dump (&output_stream, eDescriptionLevelBrief);
+ output_stream.Printf (") stopped.\n");
}
+
+ // Pop the process IO handler
+ pop_process_io_handler = true;
}
break;
}
}
- }
- if (top_io_handler_hid)
- RefreshTopIOHandler();
+ if (output_stream.GetSize() || error_stream.GetSize())
+ {
+ 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());
+ }
+
+ if (top_io_handler_hid)
+ RefreshTopIOHandler();
+ }
+
+ if (pop_process_io_handler)
+ process_sp->PopProcessIOHandler();
+ }
}
void
diff --git a/source/Core/EmulateInstruction.cpp b/source/Core/EmulateInstruction.cpp
index bf6c6d88b563..8349f54de4c7 100644
--- a/source/Core/EmulateInstruction.cpp
+++ b/source/Core/EmulateInstruction.cpp
@@ -75,7 +75,7 @@ EmulateInstruction::ReadRegister (const RegisterInfo *reg_info, RegisterValue& r
}
bool
-EmulateInstruction::ReadRegister (uint32_t reg_kind, uint32_t reg_num, RegisterValue& reg_value)
+EmulateInstruction::ReadRegister (lldb::RegisterKind reg_kind, uint32_t reg_num, RegisterValue& reg_value)
{
RegisterInfo reg_info;
if (GetRegisterInfo(reg_kind, reg_num, reg_info))
@@ -84,7 +84,7 @@ EmulateInstruction::ReadRegister (uint32_t reg_kind, uint32_t reg_num, RegisterV
}
uint64_t
-EmulateInstruction::ReadRegisterUnsigned (uint32_t reg_kind,
+EmulateInstruction::ReadRegisterUnsigned (lldb::RegisterKind reg_kind,
uint32_t reg_num,
uint64_t fail_value,
bool *success_ptr)
@@ -122,7 +122,7 @@ EmulateInstruction::WriteRegister (const Context &context,
bool
EmulateInstruction::WriteRegister (const Context &context,
- uint32_t reg_kind,
+ lldb::RegisterKind reg_kind,
uint32_t reg_num,
const RegisterValue& reg_value)
{
@@ -135,7 +135,7 @@ EmulateInstruction::WriteRegister (const Context &context,
bool
EmulateInstruction::WriteRegisterUnsigned (const Context &context,
- uint32_t reg_kind,
+ lldb::RegisterKind reg_kind,
uint32_t reg_num,
uint64_t uint_value)
{
@@ -392,7 +392,8 @@ EmulateInstruction::ReadRegisterDefault (EmulateInstruction *instruction,
{
StreamFile strm (stdout, false);
strm.Printf (" Read Register (%s)\n", reg_info->name);
- uint32_t reg_kind, reg_num;
+ lldb::RegisterKind reg_kind;
+ uint32_t reg_num;
if (GetBestRegisterKindAndNumber (reg_info, reg_kind, reg_num))
reg_value.SetUInt64((uint64_t)reg_kind << 24 | reg_num);
else
@@ -608,7 +609,7 @@ EmulateInstruction::SetInstruction (const Opcode &opcode, const Address &inst_ad
bool
EmulateInstruction::GetBestRegisterKindAndNumber (const RegisterInfo *reg_info,
- uint32_t &reg_kind,
+ lldb::RegisterKind &reg_kind,
uint32_t &reg_num)
{
// Generic and DWARF should be the two most popular register kinds when
@@ -653,7 +654,8 @@ EmulateInstruction::GetBestRegisterKindAndNumber (const RegisterInfo *reg_info,
uint32_t
EmulateInstruction::GetInternalRegisterNumber (RegisterContext *reg_ctx, const RegisterInfo &reg_info)
{
- uint32_t reg_kind, reg_num;
+ lldb::RegisterKind reg_kind;
+ uint32_t reg_num;
if (reg_ctx && GetBestRegisterKindAndNumber (&reg_info, reg_kind, reg_num))
return reg_ctx->ConvertRegisterKindToRegisterNumber (reg_kind, reg_num);
return LLDB_INVALID_REGNUM;
diff --git a/source/Core/Error.cpp b/source/Core/Error.cpp
index 7aabe5b386d4..03cfd41b288d 100644
--- a/source/Core/Error.cpp
+++ b/source/Core/Error.cpp
@@ -21,7 +21,7 @@
#include <cerrno>
#include <cstdarg>
-#if defined (__arm__) && defined (__APPLE__)
+#if (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) && defined (__APPLE__)
#include <SpringBoardServices/SpringBoardServer.h>
#endif
@@ -264,6 +264,35 @@ Error::SetMachError (uint32_t err)
m_string.clear();
}
+void
+Error::SetExpressionError (lldb::ExpressionResults result, const char *mssg)
+{
+ m_code = result;
+ m_type = eErrorTypeExpression;
+ m_string = mssg;
+}
+
+int
+Error::SetExpressionErrorWithFormat (lldb::ExpressionResults result, const char *format, ...)
+{
+ int length = 0;
+
+ if (format && format[0])
+ {
+ va_list args;
+ va_start (args, format);
+ length = SetErrorStringWithVarArg (format, args);
+ va_end (args);
+ }
+ else
+ {
+ m_string.clear();
+ }
+ m_code = result;
+ m_type = eErrorTypeExpression;
+ return length;
+}
+
//----------------------------------------------------------------------
// Set accesssor for the error value and type.
//----------------------------------------------------------------------
diff --git a/source/Core/Event.cpp b/source/Core/Event.cpp
index 2d4899dd6dcb..bf5ff222a122 100644
--- a/source/Core/Event.cpp
+++ b/source/Core/Event.cpp
@@ -57,20 +57,19 @@ Event::Dump (Stream *s) const
StreamString event_name;
if (m_broadcaster->GetEventNames (event_name, m_type, false))
s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x (%s), data = ",
- this,
- m_broadcaster,
+ static_cast<const void*>(this),
+ static_cast<void*>(m_broadcaster),
m_broadcaster->GetBroadcasterName().GetCString(),
- m_type,
- event_name.GetString().c_str());
+ m_type, event_name.GetString().c_str());
else
s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x, data = ",
- this,
- m_broadcaster,
- m_broadcaster->GetBroadcasterName().GetCString(),
- m_type);
+ static_cast<const void*>(this),
+ static_cast<void*>(m_broadcaster),
+ m_broadcaster->GetBroadcasterName().GetCString(), m_type);
}
else
- s->Printf("%p Event: broadcaster = NULL, type = 0x%8.8x, data = ", this, m_type);
+ s->Printf("%p Event: broadcaster = NULL, type = 0x%8.8x, data = ",
+ static_cast<const void*>(this), m_type);
if (m_data_ap.get() == NULL)
s->Printf ("<NULL>");
diff --git a/source/Core/FastDemangle.cpp b/source/Core/FastDemangle.cpp
new file mode 100644
index 000000000000..00a75425b689
--- /dev/null
+++ b/source/Core/FastDemangle.cpp
@@ -0,0 +1,2203 @@
+//===-- FastDemangle.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+//#define DEBUG_FAILURES 1
+//#define DEBUG_SUBSTITUTIONS 1
+//#define DEBUG_TEMPLATE_ARGS 1
+//#define DEBUG_HIGHWATER 1
+//#define DEBUG_REORDERING 1
+
+namespace {
+
+/// @brief Represents the collection of qualifiers on a type
+
+enum Qualifiers
+{
+ QualifierNone = 0,
+ QualifierConst = 1,
+ QualifierRestrict = 2,
+ QualifierVolatile = 4,
+ QualifierReference = 8,
+ QualifierRValueReference = 16,
+ QualifierPointer = 32
+};
+
+/// @brief Categorizes the recognized operators
+
+enum class OperatorKind
+{
+ Unary,
+ Postfix,
+ Binary,
+ Ternary,
+ Other,
+ ConversionOperator,
+ Vendor,
+ NoMatch
+};
+
+/// @brief Represents one of the recognized two-character operator
+/// abbreviations used when parsing operators as names and expressions
+
+struct Operator
+{
+ const char * name;
+ OperatorKind kind;
+};
+
+/// @brief Represents a range of characters in the output buffer, typically for
+/// use with RewriteRange()
+
+struct BufferRange
+{
+ int offset;
+ int length;
+};
+
+/// @brief Transient state required while parsing a name
+
+struct NameState
+{
+ bool parse_function_params;
+ bool is_last_generic;
+ bool has_no_return_type;
+ BufferRange last_name_range;
+};
+
+/// @brief LLDB's fast C++ demangler
+///
+/// This is an incomplete implementation designed to speed up the demangling
+/// process that is often a bottleneck when LLDB stops a process for the first
+/// time. Where the implementation doesn't know how to demangle a symbol it
+/// fails gracefully to allow the caller to fall back to the existing demangler.
+///
+/// Over time the full mangling spec should be supported without compromising
+/// performance for the most common cases.
+
+class SymbolDemangler
+{
+public:
+
+ //----------------------------------------------------
+ // Public API
+ //----------------------------------------------------
+
+ /// @brief Create a SymbolDemangler
+ ///
+ /// The newly created demangler allocates and owns scratch memory sufficient
+ /// for demangling typical symbols. Additional memory will be allocated if
+ /// needed and managed by the demangler instance.
+
+ SymbolDemangler()
+ {
+ buffer = (char *) malloc(8192);
+ buffer_end = buffer + 8192;
+ owns_buffer = true;
+
+ rewrite_ranges = (BufferRange *) malloc(128 * sizeof(BufferRange));
+ rewrite_ranges_size = 128;
+ owns_rewrite_ranges = true;
+ }
+
+ /// @brief Create a SymbolDemangler that uses provided scratch memory
+ ///
+ /// The provided memory is not owned by the demangler. It will be
+ /// overwritten during calls to GetDemangledCopy() but can be used for
+ /// other purposes between calls. The provided memory will not be freed
+ /// when this instance is destroyed.
+ ///
+ /// If demangling a symbol requires additional space it will be allocated
+ /// and managed by the demangler instance.
+ ///
+ /// @param storage_ptr Valid pointer to at least storage_size bytes of
+ /// space that the SymbolDemangler can use during demangling
+ ///
+ /// @param storage_size Number of bytes of space available scratch memory
+ /// referenced by storage_ptr
+
+ SymbolDemangler(void * storage_ptr, int storage_size)
+ {
+ // Use up to 1/8th of the provided space for rewrite ranges
+ rewrite_ranges_size = (storage_size >> 3) / sizeof(BufferRange);
+ rewrite_ranges = (BufferRange *) storage_ptr;
+ owns_rewrite_ranges = false;
+
+ // Use the rest for the character buffer
+ buffer = (char *) storage_ptr + rewrite_ranges_size * sizeof(BufferRange);
+ buffer_end = (const char *)storage_ptr + storage_size;
+ owns_buffer = false;
+ }
+
+ /// @brief Destroys the SymbolDemangler and deallocates any scratch
+ /// memory that it owns
+
+ ~SymbolDemangler()
+ {
+ if (owns_buffer) free(buffer);
+ if (owns_rewrite_ranges) free(rewrite_ranges);
+ }
+
+#ifdef DEBUG_HIGHWATER
+ int highwater_store = 0;
+ int highwater_buffer = 0;
+#endif
+
+ /// @brief Parses the provided mangled name and returns a newly allocated
+ /// demangling
+ ///
+ /// @param mangled_name Valid null-terminated C++ mangled name following
+ /// the Itanium C++ ABI mangling specification as implemented by Clang
+ ///
+ /// @result Newly allocated null-terminated demangled name when demangling
+ /// is succesful, and nullptr when demangling fails. The caller is
+ /// responsible for freeing the allocated memory.
+
+ char * GetDemangledCopy(const char * mangled_name,
+ long mangled_name_length = 0)
+ {
+ if (!ParseMangling(mangled_name, mangled_name_length)) return nullptr;
+
+#ifdef DEBUG_HIGHWATER
+ int rewrite_count = next_substitute_index +
+ (rewrite_ranges_size - 1 - next_template_arg_index);
+ int buffer_size = (int)(write_ptr - buffer);
+ if (rewrite_count > highwater_store) highwater_store = rewrite_count;
+ if (buffer_size > highwater_buffer) highwater_buffer = buffer_size;
+#endif
+
+ int length = (int)(write_ptr - buffer);
+ char * copy = (char *)malloc(length + 1);
+ memcpy(copy, buffer, length);
+ copy[length] = '\0';
+ return copy;
+ }
+
+private:
+
+ //----------------------------------------------------
+ // Grow methods
+ //
+ // Manage the storage used during demangling
+ //----------------------------------------------------
+
+ void GrowBuffer(long min_growth = 0)
+ {
+ // By default, double the size of the buffer
+ long growth = buffer_end - buffer;
+
+ // Avoid growing by more than 1MB at a time
+ if (growth > 1 << 20) growth = 1 << 20;
+
+ // ... but never grow by less than requested,
+ // or 1K, whichever is greater
+ if (min_growth < 1024) min_growth = 1024;
+ if (growth < min_growth) growth = min_growth;
+
+ // Allocate the new buffer and migrate content
+ long new_size = (buffer_end - buffer) + growth;
+ char * new_buffer = (char *)malloc(new_size);
+ memcpy(new_buffer, buffer, write_ptr - buffer);
+ if (owns_buffer) free(buffer);
+ owns_buffer = true;
+
+ // Update references to the new buffer
+ write_ptr = new_buffer + (write_ptr - buffer);
+ buffer = new_buffer;
+ buffer_end = buffer + new_size;
+ }
+
+ void GrowRewriteRanges()
+ {
+ // By default, double the size of the array
+ int growth = rewrite_ranges_size;
+
+ // Apply reasonable minimum and maximum sizes for growth
+ if (growth > 128) growth = 128;
+ if (growth < 16) growth = 16;
+
+ // Allocate the new array and migrate content
+ int bytes = (rewrite_ranges_size + growth) * sizeof(BufferRange);
+ BufferRange * new_ranges = (BufferRange *) malloc(bytes);
+ for (int index = 0; index < next_substitute_index; index++)
+ {
+ new_ranges[index] = rewrite_ranges[index];
+ }
+ for (int index = rewrite_ranges_size - 1;
+ index > next_template_arg_index; index--)
+ {
+ new_ranges[index + growth] = rewrite_ranges[index];
+ }
+ if (owns_rewrite_ranges) free(rewrite_ranges);
+ owns_rewrite_ranges = true;
+
+ // Update references to the new array
+ rewrite_ranges = new_ranges;
+ rewrite_ranges_size += growth;
+ next_template_arg_index += growth;
+ }
+
+ //----------------------------------------------------
+ // Range and state management
+ //----------------------------------------------------
+
+ int GetStartCookie()
+ {
+ return (int)(write_ptr - buffer);
+ }
+
+ BufferRange EndRange(int start_cookie)
+ {
+ return { start_cookie, (int)(write_ptr - (buffer + start_cookie)) };
+ }
+
+ void ReorderRange(BufferRange source_range, int insertion_point_cookie)
+ {
+ // Ensure there's room the preserve the source range
+ if (write_ptr + source_range.length > buffer_end)
+ {
+ GrowBuffer(write_ptr + source_range.length - buffer_end);
+ }
+
+ // Reorder the content
+ memcpy(write_ptr, buffer + source_range.offset, source_range.length);
+ memmove(buffer + insertion_point_cookie + source_range.length,
+ buffer + insertion_point_cookie,
+ source_range.offset - insertion_point_cookie);
+ memcpy(buffer + insertion_point_cookie, write_ptr, source_range.length);
+
+ // Fix up rewritable ranges, covering both substitutions and templates
+ int index = 0;
+ while (true)
+ {
+ if (index == next_substitute_index) index = next_template_arg_index + 1;
+ if (index == rewrite_ranges_size) break;
+
+ // Affected ranges are either shuffled forward when after the
+ // insertion but before the source, or backward when inside the
+ // source
+ int candidate_offset = rewrite_ranges[index].offset;
+ if (candidate_offset >= insertion_point_cookie)
+ {
+ if (candidate_offset < source_range.offset)
+ {
+ rewrite_ranges[index].offset += source_range.length;
+ }
+ else if (candidate_offset >= source_range.offset)
+ {
+ rewrite_ranges[index].offset -=
+ (source_range.offset - insertion_point_cookie);
+ }
+ }
+ ++index;
+ }
+ }
+
+ void EndSubstitution(int start_cookie)
+ {
+ if (next_substitute_index == next_template_arg_index) GrowRewriteRanges();
+
+ int index = next_substitute_index++;
+ rewrite_ranges[index] = EndRange(start_cookie);
+#ifdef DEBUG_SUBSTITUTIONS
+ printf("Saved substitution # %d = %.*s\n", index,
+ rewrite_ranges[index].length, buffer + start_cookie);
+#endif
+ }
+
+ void EndTemplateArg(int start_cookie)
+ {
+ if (next_substitute_index == next_template_arg_index) GrowRewriteRanges();
+
+ int index = next_template_arg_index--;
+ rewrite_ranges[index] = EndRange(start_cookie);
+#ifdef DEBUG_TEMPLATE_ARGS
+ printf("Saved template arg # %d = %.*s\n",
+ rewrite_ranges_size - index - 1,
+ rewrite_ranges[index].length, buffer + start_cookie);
+#endif
+ }
+
+ void ResetTemplateArgs()
+ {
+ //TODO: this works, but is it the right thing to do?
+ // Should we push/pop somehow at the call sites?
+ next_template_arg_index = rewrite_ranges_size - 1;
+ }
+
+ //----------------------------------------------------
+ // Write methods
+ //
+ // Appends content to the existing output buffer
+ //----------------------------------------------------
+
+ void Write(char character)
+ {
+ if (write_ptr == buffer_end) GrowBuffer();
+ *write_ptr++ = character;
+ }
+
+ void Write(const char * content)
+ {
+ Write(content, strlen(content));
+ }
+
+ void Write(const char * content, long content_length)
+ {
+ char * end_write_ptr = write_ptr + content_length;
+ if (end_write_ptr > buffer_end)
+ {
+ GrowBuffer(end_write_ptr - buffer_end);
+ end_write_ptr = write_ptr + content_length;
+ }
+ memcpy(write_ptr, content, content_length);
+ write_ptr = end_write_ptr;
+ }
+#define WRITE(x) Write(x, sizeof(x) - 1)
+
+ void WriteTemplateStart()
+ {
+ Write('<');
+ }
+
+ void WriteTemplateEnd()
+ {
+ // Put a space between terminal > characters when nesting templates
+ if (write_ptr != buffer && *(write_ptr - 1) == '>') WRITE(" >");
+ else Write('>');
+ }
+
+ void WriteCommaSpace()
+ {
+ WRITE(", ");
+ }
+
+ void WriteNamespaceSeparator()
+ {
+ WRITE("::");
+ }
+
+ void WriteStdPrefix()
+ {
+ WRITE("std::");
+ }
+
+ void WriteQualifiers(int qualifiers, bool space_before_reference = true)
+ {
+ if (qualifiers & QualifierPointer) Write('*');
+ if (qualifiers & QualifierConst) WRITE(" const");
+ if (qualifiers & QualifierVolatile) WRITE(" volatile");
+ if (qualifiers & QualifierRestrict) WRITE(" restrict");
+ if (qualifiers & QualifierReference)
+ {
+ if (space_before_reference) WRITE(" &");
+ else Write('&');
+ }
+ if (qualifiers & QualifierRValueReference)
+ {
+ if (space_before_reference) WRITE(" &&");
+ else WRITE("&&");
+ }
+ }
+
+ //----------------------------------------------------
+ // Rewrite methods
+ //
+ // Write another copy of content already present
+ // earlier in the output buffer
+ //----------------------------------------------------
+
+ void RewriteRange(BufferRange range)
+ {
+ Write(buffer + range.offset, range.length);
+ }
+
+ bool RewriteSubstitution(int index)
+ {
+ if (index < 0 || index >= next_substitute_index)
+ {
+#ifdef DEBUG_FAILURES
+ printf("*** Invalid substitution #%d\n", index);
+#endif
+ return false;
+ }
+ RewriteRange(rewrite_ranges[index]);
+ return true;
+ }
+
+ bool RewriteTemplateArg(int template_index)
+ {
+ int index = rewrite_ranges_size - 1 - template_index;
+ if (template_index < 0 || index <= next_template_arg_index)
+ {
+#ifdef DEBUG_FAILURES
+ printf("*** Invalid template arg reference #%d\n", template_index);
+#endif
+ return false;
+ }
+ RewriteRange(rewrite_ranges[index]);
+ return true;
+ }
+
+ //----------------------------------------------------
+ // TryParse methods
+ //
+ // Provide information with return values instead of
+ // writing to the output buffer
+ //
+ // Values indicating failure guarantee that the pre-
+ // call read_ptr is unchanged
+ //----------------------------------------------------
+
+ int TryParseNumber()
+ {
+ unsigned char digit = *read_ptr - '0';
+ if (digit > 9) return -1;
+
+ int count = digit;
+ while (true)
+ {
+ digit = *++read_ptr - '0';
+ if (digit > 9) break;
+
+ count = count * 10 + digit;
+ }
+ return count;
+ }
+
+ int TryParseBase36Number()
+ {
+ char digit = *read_ptr;
+ int count;
+ if (digit >= '0' && digit <= '9') count = digit -= '0';
+ else if (digit >= 'A' && digit <= 'Z') count = digit -= ('A' - 10);
+ else return -1;
+
+ while (true)
+ {
+ digit = *++read_ptr;
+ if (digit >= '0' && digit <= '9') digit -= '0';
+ else if (digit >= 'A' && digit <= 'Z') digit -= ('A' - 10);
+ else break;
+
+ count = count * 36 + digit;
+ }
+ return count;
+ }
+
+ // <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)
+ // ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
+ // ::= u <source-name> # vendor extended type
+
+ const char * TryParseBuiltinType()
+ {
+ switch (*read_ptr++)
+ {
+ case 'v': return "void";
+ case 'w': return "wchar_t";
+ case 'b': return "bool";
+ case 'c': return "char";
+ case 'a': return "signed char";
+ case 'h': return "unsigned char";
+ case 's': return "short";
+ case 't': return "unsigned short";
+ case 'i': return "int";
+ case 'j': return "unsigned int";
+ case 'l': return "long";
+ case 'm': return "unsigned long";
+ case 'x': return "long long";
+ case 'y': return "unsigned long long";
+ case 'n': return "__int128";
+ case 'o': return "unsigned __int128";
+ case 'f': return "float";
+ case 'd': return "double";
+ case 'e': return "long double";
+ case 'g': return "__float128";
+ case 'z': return "...";
+ case 'D':
+ {
+ switch (*read_ptr++)
+ {
+ case 'd': return "decimal64";
+ case 'e': return "decimal128";
+ case 'f': return "decimal32";
+ case 'h': return "decimal16";
+ case 'i': return "char32_t";
+ case 's': return "char16_t";
+ case 'a': return "auto";
+ case 'c': return "decltype(auto)";
+ case 'n': return "std::nullptr_t";
+ default:
+ --read_ptr;
+ }
+ }
+ }
+ --read_ptr;
+ return nullptr;
+ }
+
+ // <operator-name>
+ // ::= aa # &&
+ // ::= ad # & (unary)
+ // ::= an # &
+ // ::= aN # &=
+ // ::= aS # =
+ // ::= cl # ()
+ // ::= cm # ,
+ // ::= co # ~
+ // ::= da # delete[]
+ // ::= de # * (unary)
+ // ::= dl # delete
+ // ::= dv # /
+ // ::= dV # /=
+ // ::= eo # ^
+ // ::= eO # ^=
+ // ::= eq # ==
+ // ::= ge # >=
+ // ::= gt # >
+ // ::= ix # []
+ // ::= le # <=
+ // ::= 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 # >>=
+ // ::= cv <type> # (cast)
+ // ::= v <digit> <source-name> # vendor extended operator
+
+ Operator TryParseOperator()
+ {
+ switch (*read_ptr++)
+ {
+ case 'a':
+ switch (*read_ptr++)
+ {
+ case 'a': return { "&&", OperatorKind::Binary };
+ case 'd': return { "&", OperatorKind::Unary };
+ case 'n': return { "&", OperatorKind::Binary };
+ case 'N': return { "&=", OperatorKind::Binary };
+ case 'S': return { "=", OperatorKind::Binary };
+ }
+ --read_ptr;
+ break;
+ case 'c':
+ switch (*read_ptr++)
+ {
+ case 'l': return { "()", OperatorKind::Other };
+ case 'm': return { ",", OperatorKind::Other };
+ case 'o': return { "~", OperatorKind::Unary };
+ case 'v': return { nullptr, OperatorKind::ConversionOperator };
+ }
+ --read_ptr;
+ break;
+ case 'd':
+ switch (*read_ptr++)
+ {
+ case 'a': return { " delete[]", OperatorKind::Other };
+ case 'e': return { "*", OperatorKind::Unary };
+ case 'l': return { " delete", OperatorKind::Other };
+ case 'v': return { "/", OperatorKind::Binary };
+ case 'V': return { "/=", OperatorKind::Binary };
+ }
+ --read_ptr;
+ break;
+ case 'e':
+ switch (*read_ptr++)
+ {
+ case 'o': return { "^", OperatorKind::Binary };
+ case 'O': return { "^=", OperatorKind::Binary };
+ case 'q': return { "==", OperatorKind::Binary };
+ }
+ --read_ptr;
+ break;
+ case 'g':
+ switch (*read_ptr++)
+ {
+ case 'e': return { ">=", OperatorKind::Binary };
+ case 't': return { ">", OperatorKind::Binary };
+ }
+ --read_ptr;
+ break;
+ case 'i':
+ switch (*read_ptr++)
+ {
+ case 'x': return { "[]", OperatorKind::Other };
+ }
+ --read_ptr;
+ break;
+ case 'l':
+ switch (*read_ptr++)
+ {
+ case 'e': return { "<=", OperatorKind::Binary };
+ case 's': return { "<<", OperatorKind::Binary };
+ case 'S': return { "<<=", OperatorKind::Binary };
+ case 't': return { "<", OperatorKind::Binary };
+ // case 'i': return { "?", OperatorKind::Binary };
+ }
+ --read_ptr;
+ break;
+ case 'm':
+ switch (*read_ptr++)
+ {
+ case 'i': return { "-", OperatorKind::Binary };
+ case 'I': return { "-=", OperatorKind::Binary };
+ case 'l': return { "*", OperatorKind::Binary };
+ case 'L': return { "*=", OperatorKind::Binary };
+ case 'm': return { "--", OperatorKind::Postfix };
+ }
+ --read_ptr;
+ break;
+ case 'n':
+ switch (*read_ptr++)
+ {
+ case 'a': return { " new[]", OperatorKind::Other };
+ case 'e': return { "!=", OperatorKind::Binary };
+ case 'g': return { "-", OperatorKind::Unary };
+ case 't': return { "!", OperatorKind::Unary };
+ case 'w': return { " new", OperatorKind::Other };
+ }
+ --read_ptr;
+ break;
+ case 'o':
+ switch (*read_ptr++)
+ {
+ case 'o': return { "||", OperatorKind::Binary };
+ case 'r': return { "|", OperatorKind::Binary };
+ case 'R': return { "|=", OperatorKind::Binary };
+ }
+ --read_ptr;
+ break;
+ case 'p':
+ switch (*read_ptr++)
+ {
+ case 'm': return { "->*", OperatorKind::Binary };
+ case 's': return { "+", OperatorKind::Unary };
+ case 'l': return { "+", OperatorKind::Binary };
+ case 'L': return { "+=", OperatorKind::Binary };
+ case 'p': return { "++", OperatorKind::Postfix };
+ case 't': return { "->", OperatorKind::Binary };
+ }
+ --read_ptr;
+ break;
+ case 'q':
+ switch (*read_ptr++)
+ {
+ case 'u': return { "?", OperatorKind::Ternary };
+ }
+ --read_ptr;
+ break;
+ case 'r':
+ switch (*read_ptr++)
+ {
+ case 'm': return { "%", OperatorKind::Binary };
+ case 'M': return { "%=", OperatorKind::Binary };
+ case 's': return { ">>", OperatorKind::Binary };
+ case 'S': return { ">=", OperatorKind::Binary };
+ }
+ --read_ptr;
+ break;
+ case 'v':
+ char digit = *read_ptr;
+ if (digit >= '0' && digit <= '9')
+ {
+ read_ptr++;
+ return { nullptr, OperatorKind::Vendor };
+ }
+ --read_ptr;
+ break;
+ }
+ --read_ptr;
+ return { nullptr, OperatorKind::NoMatch };
+ }
+
+ // <CV-qualifiers> ::= [r] [V] [K]
+ // <ref-qualifier> ::= R # & ref-qualifier
+ // <ref-qualifier> ::= O # && ref-qualifier
+
+ int TryParseQualifiers(bool allow_cv, bool allow_ro)
+ {
+ int qualifiers = QualifierNone;
+ char next = *read_ptr;
+ if (allow_cv)
+ {
+ if (next == 'r') // restrict
+ {
+ qualifiers |= QualifierRestrict;
+ next = *++read_ptr;
+ }
+ if (next == 'V') // volatile
+ {
+ qualifiers |= QualifierVolatile;
+ next = *++read_ptr;
+ }
+ if (next == 'K') // const
+ {
+ qualifiers |= QualifierConst;
+ next = *++read_ptr;
+ }
+ }
+ if (allow_ro)
+ {
+ if (next == 'R')
+ {
+ ++read_ptr;
+ qualifiers |= QualifierReference;
+ }
+ else if (next =='O')
+ {
+ ++read_ptr;
+ qualifiers |= QualifierRValueReference;
+ }
+ }
+ return qualifiers;
+ }
+
+ // <discriminator> := _ <non-negative number> # when number < 10
+ // := __ <non-negative number> _ # when number >= 10
+ // extension := decimal-digit+
+
+ int TryParseDiscriminator()
+ {
+ const char * discriminator_start = read_ptr;
+
+ // Test the extension first, since it's what Clang uses
+ int discriminator_value = TryParseNumber();
+ if (discriminator_value != -1) return discriminator_value;
+
+ char next = *read_ptr;
+ if (next == '_')
+ {
+ next = *++read_ptr;
+ if (next == '_')
+ {
+ ++read_ptr;
+ discriminator_value = TryParseNumber();
+ if (discriminator_value != -1 && *read_ptr++ != '_')
+ {
+ return discriminator_value;
+ }
+ }
+ else if (next >= '0' && next <= '9')
+ {
+ ++read_ptr;
+ return next - '0';
+ }
+ }
+
+ // Not a valid discriminator
+ read_ptr = discriminator_start;
+ return -1;
+ }
+
+ //----------------------------------------------------
+ // Parse methods
+ //
+ // Consume input starting from read_ptr and produce
+ // buffered output at write_ptr
+ //
+ // Failures return false and may leave read_ptr in an
+ // indeterminate state
+ //----------------------------------------------------
+
+ bool Parse(char character)
+ {
+ if (*read_ptr++ == character) return true;
+#ifdef DEBUG_FAILURES
+ printf("*** Expected '%c'\n", character);
+#endif
+ return false;
+ }
+
+ // <number> ::= [n] <non-negative decimal integer>
+
+ bool ParseNumber(bool allow_negative = false)
+ {
+ if (allow_negative && *read_ptr == 'n')
+ {
+ Write('-');
+ ++read_ptr;
+ }
+ const char * before_digits = read_ptr;
+ while (true)
+ {
+ unsigned char digit = *read_ptr - '0';
+ if (digit > 9) break;
+ ++read_ptr;
+ }
+ if (int digit_count = (int)(read_ptr - before_digits))
+ {
+ Write(before_digits, digit_count);
+ return true;
+ }
+#ifdef DEBUG_FAILURES
+ printf("*** Expected number\n");
+#endif
+ return false;
+ }
+
+ // <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> >
+
+ bool ParseSubstitution()
+ {
+ const char * substitution;
+ switch (*read_ptr)
+ {
+ case 'a': substitution = "std::allocator"; break;
+ case 'b': substitution = "std::basic_string"; break;
+ case 's': substitution = "std::string"; break;
+ case 'i': substitution = "std::istream"; break;
+ case 'o': substitution = "std::ostream"; break;
+ case 'd': substitution = "std::iostream"; break;
+ default:
+ // A failed attempt to parse a number will return -1 which turns out to be
+ // perfect here as S_ is the first substitution, S0_ the next and so forth
+ int substitution_index = TryParseBase36Number();
+ if (*read_ptr++ != '_')
+ {
+#ifdef DEBUG_FAILURES
+ printf("*** Expected terminal _ in substitution\n");
+#endif
+ return false;
+ }
+ return RewriteSubstitution(substitution_index + 1);
+ }
+ Write(substitution);
+ ++read_ptr;
+ return true;
+ }
+
+ // <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
+ //
+ // <bare-function-type> ::= <signature type>+ # types are possible return type, then parameter types
+
+ bool ParseFunctionType(int inner_qualifiers = QualifierNone)
+ {
+#ifdef DEBUG_FAILURES
+ printf("*** Function types not supported\n");
+#endif
+ //TODO: first steps toward an implementation follow, but they're far
+ // from complete. Function types tend to bracket other types eg:
+ // int (*)() when used as the type for "name" becomes int (*name)().
+ // This makes substitution et al ... interesting.
+ return false;
+
+ if (*read_ptr == 'Y') ++read_ptr;;
+
+ int return_type_start_cookie = GetStartCookie();
+ if (!ParseType()) return false;
+ Write(' ');
+
+ int insert_cookie = GetStartCookie();
+ Write('(');
+ bool first_param = true;
+ int qualifiers = QualifierNone;
+ while (true)
+ {
+ switch (*read_ptr)
+ {
+ case 'E':
+ ++read_ptr;
+ Write(')');
+ break;
+ case 'v':
+ ++read_ptr;
+ continue;
+ case 'R':
+ case 'O':
+ if (*(read_ptr + 1) == 'E')
+ {
+ qualifiers = TryParseQualifiers(false, true);
+ Parse('E');
+ break;
+ }
+ // fallthrough
+ default:
+ {
+ if (first_param) first_param = false;
+ else WriteCommaSpace();
+
+ if (!ParseType()) return false;
+ continue;
+ }
+ }
+ break;
+ }
+
+ if (qualifiers)
+ {
+ WriteQualifiers(qualifiers);
+ EndSubstitution(return_type_start_cookie);
+ }
+
+ if (inner_qualifiers)
+ {
+ int qualifier_start_cookie = GetStartCookie();
+ Write('(');
+ WriteQualifiers(inner_qualifiers);
+ Write(')');
+ ReorderRange(EndRange(qualifier_start_cookie), insert_cookie);
+ }
+ return true;
+ }
+
+ // <array-type> ::= A <positive dimension number> _ <element type>
+ // ::= A [<dimension expression>] _ <element type>
+
+ bool ParseArrayType(int qualifiers = QualifierNone)
+ {
+#ifdef DEBUG_FAILURES
+ printf("*** Array type unsupported\n");
+#endif
+ //TODO: We fail horribly when recalling these as substitutions or
+ // templates and trying to constify them eg:
+ // _ZN4llvm2cl5applyIA28_cNS0_3optIbLb0ENS0_6parserIbEEEEEEvRKT_PT0_
+ //
+ //TODO: Chances are we don't do any better with references and pointers
+ // that should be type (&) [] instead of type & []
+
+ return false;
+
+ if (*read_ptr == '_')
+ {
+ ++read_ptr;
+ if (!ParseType()) return false;
+ if (qualifiers) WriteQualifiers(qualifiers);
+ WRITE(" []");
+ return true;
+ }
+ else
+ {
+ const char * before_digits = read_ptr;
+ if (TryParseNumber() != -1)
+ {
+ const char * after_digits = read_ptr;
+ if (!Parse('_')) return false;
+ if (!ParseType()) return false;
+ if (qualifiers) WriteQualifiers(qualifiers);
+ Write(' ');
+ Write('[');
+ Write(before_digits, after_digits - before_digits);
+ }
+ else
+ {
+ int type_insertion_cookie = GetStartCookie();
+ if (!ParseExpression()) return false;
+ if (!Parse('_')) return false;
+
+ int type_start_cookie = GetStartCookie();
+ if (!ParseType()) return false;
+ if (qualifiers) WriteQualifiers(qualifiers);
+ Write(' ');
+ Write('[');
+ ReorderRange(EndRange(type_start_cookie), type_insertion_cookie);
+ }
+ Write(']');
+ return true;
+ }
+ }
+
+ // <pointer-to-member-type> ::= M <class type> <member type>
+
+ //TODO: Determine how to handle pointers to function members correctly,
+ // currently not an issue because we don't have function types at all...
+ bool ParsePointerToMemberType()
+ {
+ int insertion_cookie = GetStartCookie();
+ Write(' ');
+ if (!ParseType()) return false;
+ WRITE("::*");
+
+ int type_cookie = GetStartCookie();
+ if (!ParseType()) return false;
+ ReorderRange(EndRange(type_cookie), insertion_cookie);
+ return true;
+ }
+
+ // <template-param> ::= T_ # first template parameter
+ // ::= T <parameter-2 non-negative number> _
+
+ bool ParseTemplateParam()
+ {
+ int count = TryParseNumber();
+ if (!Parse('_')) return false;
+
+ // When no number is present we get -1, which is convenient since
+ // T_ is the zeroth element T0_ is element 1, and so on
+ return RewriteTemplateArg(count + 1);
+ }
+
+ // <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>
+
+ bool ParseType()
+ {
+#ifdef DEBUG_FAILURES
+ const char * failed_type = read_ptr;
+#endif
+ int type_start_cookie = GetStartCookie();
+ bool suppress_substitution = false;
+
+ int qualifiers = TryParseQualifiers(true, false);
+ switch (*read_ptr)
+ {
+ case 'D':
+ ++read_ptr;
+ switch (*read_ptr++)
+ {
+ case 'p':
+ if (!ParseType()) return false;
+ break;
+ case 'T':
+ case 't':
+ case 'v':
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Unsupported type: %.3s\n", failed_type);
+#endif
+ return false;
+ }
+ break;
+ case 'T':
+ ++read_ptr;
+ if (!ParseTemplateParam()) return false;
+ break;
+ case 'M':
+ ++read_ptr;
+ if (!ParsePointerToMemberType()) return false;
+ break;
+ case 'A':
+ ++read_ptr;
+ if (!ParseArrayType()) return false;
+ break;
+ case 'F':
+ ++read_ptr;
+ if (!ParseFunctionType()) return false;
+ break;
+ case 'S':
+ if (*++read_ptr == 't')
+ {
+ ++read_ptr;
+ WriteStdPrefix();
+ if (!ParseName()) return false;
+ }
+ else
+ {
+ suppress_substitution = true;
+ if (!ParseSubstitution()) return false;
+ }
+ break;
+ case 'P':
+ {
+ switch (*++read_ptr)
+ {
+ case 'F':
+ ++read_ptr;
+ if (!ParseFunctionType(QualifierPointer)) return false;
+ break;
+ default:
+ if (!ParseType()) return false;
+ Write('*');
+ break;
+ }
+ break;
+ }
+ case 'R':
+ {
+ ++read_ptr;
+ if (!ParseType()) return false;
+ Write('&');
+ break;
+ }
+ case 'O':
+ {
+ ++read_ptr;
+ if (!ParseType()) return false;
+ Write('&');
+ Write('&');
+ break;
+ }
+ case 'C':
+ case 'G':
+ case 'U':
+#ifdef DEBUG_FAILURES
+ printf("*** Unsupported type: %.3s\n", failed_type);
+#endif
+ return false;
+ // Test for common cases to avoid TryParseBuiltinType() overhead
+ case 'N':
+ case 'Z':
+ case 'L':
+ if (!ParseName()) return false;
+ break;
+ default:
+ if (const char * builtin = TryParseBuiltinType())
+ {
+ Write(builtin);
+ suppress_substitution = true;
+ }
+ else
+ {
+ if (!ParseName()) return false;
+ }
+ break;
+ }
+
+ // Allow base substitutions to be suppressed, but always record
+ // substitutions for the qualified variant
+ if (!suppress_substitution) EndSubstitution(type_start_cookie);
+ if (qualifiers)
+ {
+ WriteQualifiers(qualifiers, false);
+ EndSubstitution(type_start_cookie);
+ }
+ return true;
+ }
+
+ // <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
+
+ bool ParseUnnamedTypeName(NameState & name_state)
+ {
+ switch (*read_ptr++)
+ {
+ case 't':
+ {
+ int cookie = GetStartCookie();
+ WRITE("'unnamed");
+ const char * before_digits = read_ptr;
+ if (TryParseNumber() != -1) Write(before_digits,
+ read_ptr - before_digits);
+ if (!Parse('_')) return false;
+ Write('\'');
+ name_state.last_name_range = EndRange(cookie);
+ return true;
+ }
+ case 'b':
+ {
+ int cookie = GetStartCookie();
+ WRITE("'block");
+ const char * before_digits = read_ptr;
+ if (TryParseNumber() != -1) Write(before_digits,
+ read_ptr - before_digits);
+ if (!Parse('_')) return false;
+ Write('\'');
+ name_state.last_name_range = EndRange(cookie);
+ return true;
+ }
+ case 'l':
+#ifdef DEBUG_FAILURES
+ printf("*** Lambda type names unsupported\n");
+#endif
+ return false;
+ }
+#ifdef DEBUG_FAILURES
+ printf("*** Unknown unnamed type %.3s\n", read_ptr - 2);
+#endif
+ return false;
+ }
+
+ // <ctor-dtor-name> ::= C1 # complete object constructor
+ // ::= C2 # base object constructor
+ // ::= C3 # complete object allocating constructor
+
+ bool ParseCtor(NameState & name_state)
+ {
+ char next = *read_ptr;
+ if (next == '1' || next == '2' || next == '3' || next == '5')
+ {
+ RewriteRange(name_state.last_name_range);
+ name_state.has_no_return_type = true;
+ ++read_ptr;
+ return true;
+ }
+#ifdef DEBUG_FAILURES
+ printf("*** Broken constructor\n");
+#endif
+ return false;
+ }
+
+ // <ctor-dtor-name> ::= D0 # deleting destructor
+ // ::= D1 # complete object destructor
+ // ::= D2 # base object destructor
+
+ bool ParseDtor(NameState & name_state)
+ {
+ char next = *read_ptr;
+ if (next == '0' || next == '1' || next == '2' || next == '5')
+ {
+ Write('~');
+ RewriteRange(name_state.last_name_range);
+ name_state.has_no_return_type = true;
+ ++read_ptr;
+ return true;
+ }
+#ifdef DEBUG_FAILURES
+ printf("*** Broken destructor\n");
+#endif
+ return false;
+ }
+
+ // See TryParseOperator()
+
+ bool ParseOperatorName(NameState & name_state)
+ {
+#ifdef DEBUG_FAILURES
+ const char * operator_ptr = read_ptr;
+#endif
+ Operator parsed_operator = TryParseOperator();
+ if (parsed_operator.name)
+ {
+ WRITE("operator");
+ Write(parsed_operator.name);
+ return true;
+ }
+
+ // Handle special operators
+ switch (parsed_operator.kind)
+ {
+ case OperatorKind::Vendor:
+ WRITE("operator ");
+ return ParseSourceName();
+ case OperatorKind::ConversionOperator:
+ ResetTemplateArgs();
+ name_state.has_no_return_type = true;
+ WRITE("operator ");
+ return ParseType();
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Unknown operator: %.2s\n", operator_ptr);
+#endif
+ return false;
+ }
+ }
+
+ // <source-name> ::= <positive length number> <identifier>
+
+ bool ParseSourceName()
+ {
+ int count = TryParseNumber();
+ if (count == -1)
+ {
+#ifdef DEBUG_FAILURES
+ printf("*** Malformed source name, missing length count\n");
+#endif
+ return false;
+ }
+
+ const char * next_read_ptr = read_ptr + count;
+ if (next_read_ptr > read_end)
+ {
+#ifdef DEBUG_FAILURES
+ printf("*** Malformed source name, premature termination\n");
+#endif
+ return false;
+ }
+
+ if (count >= 10 && strncmp(read_ptr, "_GLOBAL__N", 10) == 0) WRITE("(anonymous namespace)");
+ else Write(read_ptr, count);
+
+ read_ptr = next_read_ptr;
+ return true;
+ }
+
+ // <unqualified-name> ::= <operator-name>
+ // ::= <ctor-dtor-name>
+ // ::= <source-name>
+ // ::= <unnamed-type-name>
+
+ bool ParseUnqualifiedName(NameState & name_state)
+ {
+ // Note that these are detected directly in ParseNestedName for
+ // performance rather than switching on the same options twice
+ char next = *read_ptr;
+ switch (next)
+ {
+ case 'C':
+ ++read_ptr;
+ return ParseCtor(name_state);
+ case 'D':
+ ++read_ptr;
+ return ParseDtor(name_state);
+ case 'U':
+ ++read_ptr;
+ return ParseUnnamedTypeName(name_state);
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ int name_start_cookie = GetStartCookie();
+ if (!ParseSourceName()) return false;
+ name_state.last_name_range = EndRange(name_start_cookie);
+ return true;
+ }
+ default:
+ return ParseOperatorName(name_state);
+ };
+ }
+
+ // <unscoped-name> ::= <unqualified-name>
+ // ::= St <unqualified-name> # ::std::
+ // extension ::= StL<unqualified-name>
+
+ bool ParseUnscopedName(NameState & name_state)
+ {
+ if (*read_ptr == 'S' && *(read_ptr + 1) == 't')
+ {
+ WriteStdPrefix();
+ if (*(read_ptr += 2) == 'L') ++read_ptr;
+ }
+ return ParseUnqualifiedName(name_state);
+ }
+
+ bool ParseIntegerLiteral(const char * prefix, const char * suffix,
+ bool allow_negative)
+ {
+ if (prefix) Write(prefix);
+ if (!ParseNumber(allow_negative)) return false;
+ if (suffix) Write(suffix);
+ return Parse('E');
+ }
+
+ bool ParseBooleanLiteral()
+ {
+ switch (*read_ptr++)
+ {
+ case '0': WRITE("false"); break;
+ case '1': WRITE("true"); break;
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Boolean literal not 0 or 1\n");
+#endif
+ return false;
+ }
+ return Parse('E');
+ }
+
+ // <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
+
+ bool ParseExpressionPrimary()
+ {
+ switch (*read_ptr++)
+ {
+ case 'b': return ParseBooleanLiteral();
+ case 'x': return ParseIntegerLiteral(nullptr, "ll", true);
+ case 'l': return ParseIntegerLiteral(nullptr, "l", true);
+ case 'i': return ParseIntegerLiteral(nullptr, nullptr, true);
+ case 'n': return ParseIntegerLiteral("(__int128)", nullptr, true);
+ case 'j': return ParseIntegerLiteral(nullptr, "u", false);
+ case 'm': return ParseIntegerLiteral(nullptr, "ul", false);
+ case 'y': return ParseIntegerLiteral(nullptr, "ull", false);
+ case 'o': return ParseIntegerLiteral("(unsigned __int128)",
+ nullptr, false);
+ case '_':
+ if (*read_ptr++ == 'Z')
+ {
+ if (!ParseEncoding()) return false;
+ return Parse('E');
+ }
+ --read_ptr;
+ // fallthrough
+ case 'w':
+ case 'c':
+ case 'a':
+ case 'h':
+ case 's':
+ case 't':
+ case 'f':
+ case 'd':
+ case 'e':
+#ifdef DEBUG_FAILURES
+ printf("*** Unsupported primary expression %.5s\n", read_ptr - 1);
+#endif
+ return false;
+ case 'T':
+ // Invalid mangled name per
+ // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+#ifdef DEBUG_FAILURES
+ printf("*** Invalid primary expr encoding\n");
+#endif
+ return false;
+ default:
+ --read_ptr;
+ Write('(');
+ if (!ParseType()) return false;
+ Write(')');
+ if (!ParseNumber()) return false;
+ return Parse('E');
+ }
+ }
+
+ // <unresolved-type> ::= <template-param>
+ // ::= <decltype>
+ // ::= <substitution>
+
+ bool ParseUnresolvedType()
+ {
+ int type_start_cookie = GetStartCookie();
+ switch (*read_ptr++)
+ {
+ case 'T':
+ if (!ParseTemplateParam()) return false;
+ EndSubstitution(type_start_cookie);
+ return true;
+ case 'S':
+ {
+ if (*read_ptr != 't') return ParseSubstitution();
+
+ ++read_ptr;
+ WriteStdPrefix();
+ NameState type_name = {};
+ if (!ParseUnqualifiedName(type_name)) return false;
+ EndSubstitution(type_start_cookie);
+ return true;
+
+ }
+ case 'D':
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Unsupported unqualified type: %3s\n", read_ptr - 1);
+#endif
+ return false;
+ }
+ }
+
+ // <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>
+
+ bool ParseBaseUnresolvedName()
+ {
+#ifdef DEBUG_FAILURES
+ printf("*** Base unresolved name unsupported\n");
+#endif
+ return false;
+ }
+
+ // <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>
+
+ bool ParseUnresolvedName()
+ {
+#ifdef DEBUG_FAILURES
+ printf("*** Unresolved names not supported\n");
+#endif
+ //TODO: grammar for all of this seems unclear...
+ return false;
+
+ if (*read_ptr == 'g' && *(read_ptr + 1) == 's')
+ {
+ read_ptr += 2;
+ WriteNamespaceSeparator();
+ }
+ }
+
+ // <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>
+
+ bool ParseExpression()
+ {
+ Operator expression_operator = TryParseOperator();
+ switch (expression_operator.kind)
+ {
+ case OperatorKind::Unary:
+ Write(expression_operator.name);
+ Write('(');
+ if (!ParseExpression()) return false;
+ Write(')');
+ return true;
+ case OperatorKind::Binary:
+ if (!ParseExpression()) return false;
+ Write(expression_operator.name);
+ return ParseExpression();
+ case OperatorKind::Ternary:
+ if (!ParseExpression()) return false;
+ Write('?');
+ if (!ParseExpression()) return false;
+ Write(':');
+ return ParseExpression();
+ case OperatorKind::NoMatch:
+ break;
+ case OperatorKind::Other:
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Unsupported operator: %s\n", expression_operator.name);
+#endif
+ return false;
+ }
+
+ switch (*read_ptr++)
+ {
+ case 'T': return ParseTemplateParam();
+ case 'L': return ParseExpressionPrimary();
+ case 's':
+ if (*read_ptr++ == 'r') return ParseUnresolvedName();
+ --read_ptr;
+ // fallthrough
+ default:
+ return ParseExpressionPrimary();
+ }
+ }
+
+ // <template-arg> ::= <type> # type or template
+ // ::= X <expression> E # expression
+ // ::= <expr-primary> # simple expressions
+ // ::= J <template-arg>* E # argument pack
+ // ::= LZ <encoding> E # extension
+
+ bool ParseTemplateArg()
+ {
+ switch (*read_ptr) {
+ case 'J':
+#ifdef DEBUG_FAILURES
+ printf("*** Template argument packs unsupported\n");
+#endif
+ return false;
+ case 'X':
+ ++read_ptr;
+ if (!ParseExpression()) return false;
+ return Parse('E');
+ case 'L':
+ ++read_ptr;
+ return ParseExpressionPrimary();
+ default:
+ return ParseType();
+ }
+ }
+
+ // <template-args> ::= I <template-arg>* E
+ // extension, the abi says <template-arg>+
+
+ bool ParseTemplateArgs(bool record_template_args = false)
+ {
+ if (record_template_args) ResetTemplateArgs();
+
+ bool first_arg = true;
+ while (*read_ptr != 'E')
+ {
+ if (first_arg) first_arg = false;
+ else WriteCommaSpace();
+
+ int template_start_cookie = GetStartCookie();
+ if (!ParseTemplateArg()) return false;
+ if (record_template_args) EndTemplateArg(template_start_cookie);
+ }
+ ++read_ptr;
+ return true;
+ }
+
+ // <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>
+ //
+ // <unqualified-name> ::= <operator-name>
+ // ::= <ctor-dtor-name>
+ // ::= <source-name>
+ // ::= <unnamed-type-name>
+
+ bool ParseNestedName(NameState & name_state, bool parse_discriminator = false)
+ {
+ int qualifiers = TryParseQualifiers(true, true);
+ bool first_part = true;
+ bool suppress_substitution = true;
+ int name_start_cookie = GetStartCookie();
+ while (true)
+ {
+ char next = *read_ptr;
+ if (next == 'E')
+ {
+ ++read_ptr;
+ break;
+ }
+
+ // Record a substitution candidate for all prefixes, but not the full name
+ if (suppress_substitution) suppress_substitution = false;
+ else EndSubstitution(name_start_cookie);
+
+ if (next == 'I')
+ {
+ ++read_ptr;
+ name_state.is_last_generic = true;
+ WriteTemplateStart();
+ if (!ParseTemplateArgs(name_state.parse_function_params)) return false;
+ WriteTemplateEnd();
+ continue;
+ }
+
+ if (first_part) first_part = false;
+ else WriteNamespaceSeparator();
+
+ name_state.is_last_generic = false;
+ switch (next)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ int name_start_cookie = GetStartCookie();
+ if (!ParseSourceName()) return false;
+ name_state.last_name_range = EndRange(name_start_cookie);
+ continue;
+ }
+ case 'S':
+ if (*++read_ptr == 't')
+ {
+ WriteStdPrefix();
+ ++read_ptr;
+ if (!ParseUnqualifiedName(name_state)) return false;
+ }
+ else
+ {
+ if (!ParseSubstitution()) return false;
+ suppress_substitution = true;
+ }
+ continue;
+ case 'T':
+ ++read_ptr;
+ if (!ParseTemplateParam()) return false;
+ continue;
+ case 'C':
+ ++read_ptr;
+ if (!ParseCtor(name_state)) return false;
+ continue;
+ case 'D':
+ {
+ switch (*(read_ptr + 1))
+ {
+ case 't':
+ case 'T':
+#ifdef DEBUG_FAILURES
+ printf("*** Decltype unsupported\n");
+#endif
+ return false;
+ }
+ ++read_ptr;
+ if (!ParseDtor(name_state)) return false;
+ continue;
+ }
+ case 'U':
+ ++read_ptr;
+ if (!ParseUnnamedTypeName(name_state)) return false;
+ continue;
+ case 'L':
+ ++read_ptr;
+ if (!ParseUnqualifiedName(name_state)) return false;
+ continue;
+ default:
+ if (!ParseOperatorName(name_state)) return false;
+ }
+ }
+
+ if (parse_discriminator) TryParseDiscriminator();
+ if (name_state.parse_function_params &&
+ !ParseFunctionArgs(name_state, name_start_cookie)) return false;
+ if (qualifiers) WriteQualifiers(qualifiers);
+ return true;
+ }
+
+ // <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+ // := Z <function encoding> E s [<discriminator>]
+ // := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+
+ bool ParseLocalName(bool parse_function_params)
+ {
+ if (!ParseEncoding()) return false;
+ if (!Parse('E')) return false;
+
+ switch (*read_ptr)
+ {
+ case 's':
+ TryParseDiscriminator(); // Optional and ignored
+ WRITE("::string literal");
+ break;
+ case 'd':
+ TryParseNumber(); // Optional and ignored
+ WriteNamespaceSeparator();
+ if (!ParseName()) return false;
+ break;
+ default:
+ WriteNamespaceSeparator();
+ if (!ParseName(parse_function_params, true)) return false;
+ TryParseDiscriminator(); // Optional and ignored
+ }
+ return true;
+ }
+
+ // <name> ::= <nested-name>
+ // ::= <local-name>
+ // ::= <unscoped-template-name> <template-args>
+ // ::= <unscoped-name>
+
+ // <unscoped-template-name> ::= <unscoped-name>
+ // ::= <substitution>
+
+ bool ParseName(bool parse_function_params = false,
+ bool parse_discriminator = false)
+ {
+ NameState name_state = { parse_function_params };
+ int name_start_cookie = GetStartCookie();
+
+ switch (*read_ptr)
+ {
+ case 'N':
+ ++read_ptr;
+ return ParseNestedName(name_state, parse_discriminator);
+ case 'Z':
+ {
+ ++read_ptr;
+ if (!ParseLocalName(parse_function_params)) return false;
+ break;
+ }
+ case 'L':
+ ++read_ptr;
+ // fallthrough
+ default:
+ {
+ if (!ParseUnscopedName(name_state)) return false;
+
+ if (*read_ptr == 'I')
+ {
+ EndSubstitution(name_start_cookie);
+
+ ++read_ptr;
+ name_state.is_last_generic = true;
+ WriteTemplateStart();
+ if (!ParseTemplateArgs(parse_function_params)) return false;
+ WriteTemplateEnd();
+ }
+ break;
+ }
+ }
+ if (parse_discriminator) TryParseDiscriminator();
+ if (parse_function_params &&
+ !ParseFunctionArgs(name_state, name_start_cookie)) return false;
+ return true;
+ }
+
+ // <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
+
+ bool ParseCallOffset()
+ {
+ switch (*read_ptr++)
+ {
+ case 'h':
+ if (*read_ptr == 'n') ++read_ptr;
+ if (TryParseNumber() == -1 || *read_ptr++ != '_') break;
+ return true;
+ case 'v':
+ if (*read_ptr == 'n') ++read_ptr;
+ if (TryParseNumber() == -1 || *read_ptr++ != '_') break;
+ if (*read_ptr == 'n') ++read_ptr;
+ if (TryParseNumber() == -1 || *read_ptr++ != '_') break;
+ return true;
+ }
+#ifdef DEBUG_FAILURES
+ printf("*** Malformed call offset\n");
+#endif
+ return false;
+ }
+
+ // <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
+ // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+
+ bool ParseSpecialNameT()
+ {
+ switch (*read_ptr++)
+ {
+ case 'V':
+ WRITE("vtable for ");
+ return ParseType();
+ case 'T':
+ WRITE("VTT for ");
+ return ParseType();
+ case 'I':
+ WRITE("typeinfo for ");
+ return ParseType();
+ case 'S':
+ WRITE("typeinfo name for ");
+ return ParseType();
+ case 'c':
+ case 'C':
+#ifdef DEBUG_FAILURES
+ printf("*** Unsupported thunk or construction vtable name: %.3s\n", read_ptr - 1);
+#endif
+ return false;
+ default:
+ if (*--read_ptr == 'v')
+ {
+ WRITE("virtual thunk to ");
+ }
+ else
+ {
+ WRITE("non-virtual thunk to ");
+ }
+ if (!ParseCallOffset()) return false;
+ return ParseEncoding();
+ }
+ }
+
+ // <special-name> ::= GV <object name> # Guard variable for one-time initialization
+ // # No <type>
+ // extension ::= GR <object name> # reference temporary for object
+
+ bool ParseSpecialNameG()
+ {
+ switch (*read_ptr++)
+ {
+ case 'V':
+ WRITE("guard variable for ");
+ if (!ParseName(true)) return false;
+ break;
+ case 'R':
+ WRITE("reference temporary for ");
+ if (!ParseName(true)) return false;
+ break;
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Unknown G encoding\n");
+#endif
+ return false;
+ }
+ return true;
+ }
+
+ // <bare-function-type> ::= <signature type>+ # types are possible return type, then parameter types
+
+ bool ParseFunctionArgs(NameState & name_state, int return_insert_cookie)
+ {
+ char next = *read_ptr;
+ if (next == 'E' || next == '\0' || next == '.') return true;
+
+ // Clang has a bad habit of making unique manglings by just sticking numbers on the end of a symbol,
+ // which is ambiguous with malformed source name manglings
+ const char * before_clang_uniquing_test = read_ptr;
+ if (TryParseNumber())
+ {
+ if (*read_ptr == '\0') return true;
+ read_ptr = before_clang_uniquing_test;
+ }
+
+ if (name_state.is_last_generic && !name_state.has_no_return_type)
+ {
+ int return_type_start_cookie = GetStartCookie();
+ if (!ParseType()) return false;
+ Write(' ');
+ ReorderRange(EndRange(return_type_start_cookie),
+ return_insert_cookie);
+ }
+
+ Write('(');
+ bool first_param = true;
+ while (true)
+ {
+ switch (*read_ptr)
+ {
+ case '\0':
+ case 'E':
+ case '.':
+ break;
+ case 'v':
+ ++read_ptr;
+ continue;
+ case '_':
+ // Not a formal part of the mangling specification, but clang emits suffixes starting with _block_invoke
+ if (strncmp(read_ptr, "_block_invoke", 13) == 0)
+ {
+ read_ptr += strlen(read_ptr);
+ break;
+ }
+ // fallthrough
+ default:
+ if (first_param) first_param = false;
+ else WriteCommaSpace();
+
+ if (!ParseType()) return false;
+ continue;
+ }
+ break;
+ }
+ Write(')');
+ return true;
+ }
+
+ // <encoding> ::= <function name> <bare-function-type>
+ // ::= <data name>
+ // ::= <special-name>
+
+ bool ParseEncoding()
+ {
+ switch (*read_ptr)
+ {
+ case 'T':
+ ++read_ptr;
+ if (!ParseSpecialNameT()) return false;
+ break;
+ case 'G':
+ ++read_ptr;
+ if (!ParseSpecialNameG()) return false;
+ break;
+ default:
+ if (!ParseName(true)) return false;
+ break;
+ }
+ return true;
+ }
+
+ bool ParseMangling(const char * mangled_name, long mangled_name_length = 0)
+ {
+ if (!mangled_name_length) mangled_name_length = strlen(mangled_name);
+ read_end = mangled_name + mangled_name_length;
+ read_ptr = mangled_name;
+ write_ptr = buffer;
+ next_substitute_index = 0;
+ next_template_arg_index = rewrite_ranges_size - 1;
+
+ if (*read_ptr++ != '_' || *read_ptr++ != 'Z')
+ {
+#ifdef DEBUG_FAILURES
+ printf("*** Missing _Z prefix\n");
+#endif
+ return false;
+ }
+ if (!ParseEncoding()) return false;
+ switch (*read_ptr)
+ {
+ case '.':
+ Write(' ');
+ Write('(');
+ Write(read_ptr, read_end - read_ptr);
+ Write(')');
+ case '\0':
+ return true;
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Unparsed mangled content\n");
+#endif
+ return false;
+ }
+ }
+
+private:
+
+ // External scratch storage used during demanglings
+
+ char * buffer;
+ const char * buffer_end;
+ BufferRange * rewrite_ranges;
+ int rewrite_ranges_size;
+ bool owns_buffer;
+ bool owns_rewrite_ranges;
+
+ // Internal state used during demangling
+
+ const char * read_ptr;
+ const char * read_end;
+ char * write_ptr;
+ int next_template_arg_index;
+ int next_substitute_index;
+};
+
+} // Anonymous namespace
+
+// Public entry points referenced from Mangled.cpp
+namespace lldb_private
+{
+ char * FastDemangle(const char* mangled_name)
+ {
+ char buffer[16384];
+ SymbolDemangler demangler(buffer, sizeof(buffer));
+ return demangler.GetDemangledCopy(mangled_name);
+ }
+
+ char * FastDemangle(const char* mangled_name, long mangled_name_length)
+ {
+ char buffer[16384];
+ SymbolDemangler demangler(buffer, sizeof(buffer));
+ return demangler.GetDemangledCopy(mangled_name, mangled_name_length);
+ }
+} // lldb_private namespace
diff --git a/source/Core/IOHandler.cpp b/source/Core/IOHandler.cpp
index 168a8f67a08e..add3ad8c5ba3 100644
--- a/source/Core/IOHandler.cpp
+++ b/source/Core/IOHandler.cpp
@@ -15,6 +15,7 @@
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/IOHandler.h"
#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ValueObjectRegister.h"
@@ -157,6 +158,7 @@ IOHandlerConfirm::IOHandlerConfirm (Debugger &debugger,
NULL, // NULL editline_name means no history loaded/saved
NULL,
false, // Multi-line
+ 0,
*this),
m_default_response (default_response),
m_user_response (default_response)
@@ -311,6 +313,7 @@ IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
const char *editline_name, // Used for saving history files
const char *prompt,
bool multi_line,
+ uint32_t line_number_start,
IOHandlerDelegate &delegate) :
IOHandlerEditline(debugger,
StreamFileSP(), // Inherit input from top input reader
@@ -320,6 +323,7 @@ IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
editline_name, // Used for saving history files
prompt,
multi_line,
+ line_number_start,
delegate)
{
}
@@ -332,11 +336,13 @@ IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
const char *editline_name, // Used for saving history files
const char *prompt,
bool multi_line,
+ uint32_t line_number_start,
IOHandlerDelegate &delegate) :
IOHandler (debugger, input_sp, output_sp, error_sp, flags),
m_editline_ap (),
m_delegate (delegate),
m_prompt (),
+ m_base_line_number (line_number_start),
m_multi_line (multi_line)
{
SetPrompt(prompt);
@@ -346,16 +352,20 @@ IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
#ifndef _MSC_VER
use_editline = m_input_sp->GetFile().GetIsRealTerminal();
#else
- use_editline = true;
+ // Editline is causing issues on Windows, so use the fallback.
+ use_editline = false;
#endif
if (use_editline)
{
m_editline_ap.reset(new Editline (editline_name,
prompt ? prompt : "",
+ multi_line,
GetInputFILE (),
GetOutputFILE (),
GetErrorFILE ()));
+ if (m_base_line_number > 0)
+ m_editline_ap->ShowLineNumbers(true, m_base_line_number);
m_editline_ap->SetLineCompleteCallback (LineCompletedCallback, this);
m_editline_ap->SetAutoCompleteCallback (AutoCompleteCallback, this);
}
@@ -369,11 +379,11 @@ IOHandlerEditline::~IOHandlerEditline ()
bool
-IOHandlerEditline::GetLine (std::string &line)
+IOHandlerEditline::GetLine (std::string &line, bool &interrupted)
{
if (m_editline_ap)
{
- return m_editline_ap->GetLine(line).Success();
+ return m_editline_ap->GetLine(line, interrupted).Success();
}
else
{
@@ -401,7 +411,16 @@ IOHandlerEditline::GetLine (std::string &line)
while (!done)
{
if (fgets(buffer, sizeof(buffer), in) == NULL)
- done = true;
+ {
+ const int saved_errno = errno;
+ if (feof(in))
+ done = true;
+ else if (ferror(in))
+ {
+ if (saved_errno != EINTR)
+ done = true;
+ }
+ }
else
{
got_line = true;
@@ -491,33 +510,62 @@ IOHandlerEditline::SetPrompt (const char *p)
return true;
}
+void
+IOHandlerEditline::SetBaseLineNumber (uint32_t line)
+{
+ m_base_line_number = line;
+ if (m_editline_ap)
+ m_editline_ap->ShowLineNumbers (true, line);
+
+}
bool
-IOHandlerEditline::GetLines (StringList &lines)
+IOHandlerEditline::GetLines (StringList &lines, bool &interrupted)
{
bool success = false;
if (m_editline_ap)
{
std::string end_token;
- success = m_editline_ap->GetLines(end_token, lines).Success();
+ success = m_editline_ap->GetLines(end_token, lines, interrupted).Success();
}
else
{
LineStatus lines_status = LineStatus::Success;
+ Error error;
while (lines_status == LineStatus::Success)
{
+ // Show line numbers if we are asked to
std::string line;
- if (GetLine(line))
+ if (m_base_line_number > 0 && GetIsInteractive())
{
- lines.AppendString(line);
- Error error;
- lines_status = m_delegate.IOHandlerLinesUpdated(*this, lines, lines.GetSize() - 1, error);
+ FILE *out = GetOutputFILE();
+ if (out)
+ ::fprintf(out, "%u%s", m_base_line_number + (uint32_t)lines.GetSize(), GetPrompt() == NULL ? " " : "");
+ }
+
+ bool interrupted = false;
+ if (GetLine(line, interrupted))
+ {
+ if (interrupted)
+ {
+ lines_status = LineStatus::Done;
+ }
+ else
+ {
+ lines.AppendString(line);
+ lines_status = m_delegate.IOHandlerLinesUpdated(*this, lines, lines.GetSize() - 1, error);
+ }
}
else
{
lines_status = LineStatus::Done;
}
}
+
+ // Call the IOHandlerLinesUpdated function with UINT32_MAX as the line
+ // number to indicate all lines are complete
+ m_delegate.IOHandlerLinesUpdated(*this, lines, UINT32_MAX, error);
+
success = lines.GetSize() > 0;
}
return success;
@@ -532,13 +580,21 @@ IOHandlerEditline::Run ()
std::string line;
while (IsActive())
{
+ bool interrupted = false;
if (m_multi_line)
{
StringList lines;
- if (GetLines (lines))
+ if (GetLines (lines, interrupted))
{
- line = lines.CopyList();
- m_delegate.IOHandlerInputComplete(*this, line);
+ if (interrupted)
+ {
+ m_done = true;
+ }
+ else
+ {
+ line = lines.CopyList();
+ m_delegate.IOHandlerInputComplete(*this, line);
+ }
}
else
{
@@ -547,9 +603,10 @@ IOHandlerEditline::Run ()
}
else
{
- if (GetLine(line))
+ if (GetLine(line, interrupted))
{
- m_delegate.IOHandlerInputComplete(*this, line);
+ if (!interrupted)
+ m_delegate.IOHandlerInputComplete(*this, line);
}
else
{
@@ -562,7 +619,7 @@ IOHandlerEditline::Run ()
void
IOHandlerEditline::Hide ()
{
- if (m_editline_ap && m_editline_ap->GettingLine())
+ if (m_editline_ap)
m_editline_ap->Hide();
}
@@ -570,8 +627,10 @@ IOHandlerEditline::Hide ()
void
IOHandlerEditline::Refresh ()
{
- if (m_editline_ap && m_editline_ap->GettingLine())
+ if (m_editline_ap)
+ {
m_editline_ap->Refresh();
+ }
else
{
const char *prompt = GetPrompt();
@@ -594,11 +653,16 @@ IOHandlerEditline::Cancel ()
m_editline_ap->Interrupt ();
}
-void
+bool
IOHandlerEditline::Interrupt ()
{
+ // Let the delgate handle it first
+ if (m_delegate.IOHandlerInterrupt(*this))
+ return true;
+
if (m_editline_ap)
- m_editline_ap->Interrupt();
+ return m_editline_ap->Interrupt();
+ return false;
}
void
@@ -1308,7 +1372,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
const size_t max_length = help_delegate_ap->GetMaxLineLength();
Rect bounds = GetBounds();
bounds.Inset(1, 1);
- if (max_length + 4 < bounds.size.width)
+ if (max_length + 4 < static_cast<size_t>(bounds.size.width))
{
bounds.origin.x += (bounds.size.width - max_length + 4)/2;
bounds.size.width = max_length + 4;
@@ -1323,7 +1387,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
}
}
- if (num_lines + 2 < bounds.size.height)
+ if (num_lines + 2 < static_cast<size_t>(bounds.size.height))
{
bounds.origin.y += (bounds.size.height - num_lines + 2)/2;
bounds.size.height = num_lines + 2;
@@ -1821,9 +1885,9 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
for (size_t i=0; i<num_submenus; ++i)
{
Menu *submenu = submenus[i].get();
- if (m_max_submenu_name_length < submenu->m_name.size())
+ if (static_cast<size_t>(m_max_submenu_name_length) < submenu->m_name.size())
m_max_submenu_name_length = submenu->m_name.size();
- if (m_max_submenu_key_name_length < submenu->m_key_name.size())
+ if (static_cast<size_t>(m_max_submenu_key_name_length) < submenu->m_key_name.size())
m_max_submenu_key_name_length = submenu->m_key_name.size();
}
}
@@ -1832,9 +1896,9 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
Menu::AddSubmenu (const MenuSP &menu_sp)
{
menu_sp->m_parent = this;
- if (m_max_submenu_name_length < menu_sp->m_name.size())
+ if (static_cast<size_t>(m_max_submenu_name_length) < menu_sp->m_name.size())
m_max_submenu_name_length = menu_sp->m_name.size();
- if (m_max_submenu_key_name_length < menu_sp->m_key_name.size())
+ if (static_cast<size_t>(m_max_submenu_key_name_length) < menu_sp->m_key_name.size())
m_max_submenu_key_name_length = menu_sp->m_key_name.size();
m_submenus.push_back(menu_sp);
}
@@ -1850,7 +1914,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
if (width > 2)
{
width -= 2;
- for (size_t i=0; i< width; ++i)
+ for (int i=0; i< width; ++i)
window.PutChar(ACS_HLINE);
}
window.PutChar(ACS_RTEE);
@@ -1951,7 +2015,8 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
window.Box();
for (size_t i=0; i<num_submenus; ++i)
{
- const bool is_selected = i == selected_idx;
+ const bool is_selected =
+ (i == static_cast<size_t>(selected_idx));
window.MoveCursor(x, y + i);
if (is_selected)
{
@@ -1990,7 +2055,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
case KEY_DOWN:
case KEY_UP:
// Show last menu or first menu
- if (selected_idx < num_submenus)
+ if (selected_idx < static_cast<int>(num_submenus))
run_menu_sp = submenus[selected_idx];
else if (!submenus.empty())
run_menu_sp = submenus.front();
@@ -2000,9 +2065,9 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
case KEY_RIGHT:
{
++m_selected;
- if (m_selected >= num_submenus)
+ if (m_selected >= static_cast<int>(num_submenus))
m_selected = 0;
- if (m_selected < num_submenus)
+ if (m_selected < static_cast<int>(num_submenus))
run_menu_sp = submenus[m_selected];
else if (!submenus.empty())
run_menu_sp = submenus.front();
@@ -2015,7 +2080,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
--m_selected;
if (m_selected < 0)
m_selected = num_submenus - 1;
- if (m_selected < num_submenus)
+ if (m_selected < static_cast<int>(num_submenus))
run_menu_sp = submenus[m_selected];
else if (!submenus.empty())
run_menu_sp = submenus.front();
@@ -2069,7 +2134,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
const int start_select = m_selected;
while (++m_selected != start_select)
{
- if (m_selected >= num_submenus)
+ if (static_cast<size_t>(m_selected) >= num_submenus)
m_selected = 0;
if (m_submenus[m_selected]->GetType() == Type::Separator)
continue;
@@ -2086,7 +2151,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
const int start_select = m_selected;
while (--m_selected != start_select)
{
- if (m_selected < 0)
+ if (m_selected < static_cast<int>(0))
m_selected = num_submenus - 1;
if (m_submenus[m_selected]->GetType() == Type::Separator)
continue;
@@ -2098,7 +2163,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
break;
case KEY_RETURN:
- if (selected_idx < num_submenus)
+ if (static_cast<size_t>(selected_idx) < num_submenus)
{
if (submenus[selected_idx]->Action() == MenuActionResult::Quit)
return eQuitApplication;
@@ -2113,13 +2178,11 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
default:
{
- bool handled = false;
for (size_t i=0; i<num_submenus; ++i)
{
Menu *menu = submenus[i].get();
if (menu->GetKeyValue() == key)
{
- handled = true;
SetSelectedSubmenuIndex(i);
window.GetParent()->RemoveSubWindow(&window);
if (menu->Action() == MenuActionResult::Quit)
@@ -2288,6 +2351,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
ConstString broadcaster_class (broadcaster->GetBroadcasterClass());
if (broadcaster_class == broadcaster_class_process)
{
+ debugger.GetCommandInterpreter().UpdateExecutionContext(NULL);
update = true;
continue; // Don't get any key, just update our view
}
@@ -2302,6 +2366,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
switch (key_result)
{
case eKeyHandled:
+ debugger.GetCommandInterpreter().UpdateExecutionContext(NULL);
update = true;
break;
case eKeyNotHandled:
@@ -2493,6 +2558,7 @@ public:
TreeItem (TreeItem *parent, TreeDelegate &delegate, bool might_have_children) :
m_parent (parent),
m_delegate (delegate),
+ m_user_data (NULL),
m_identifier (0),
m_row_idx (-1),
m_children (),
@@ -2508,6 +2574,7 @@ public:
{
m_parent = rhs.m_parent;
m_delegate = rhs.m_delegate;
+ m_user_data = rhs.m_user_data;
m_identifier = rhs.m_identifier;
m_row_idx = rhs.m_row_idx;
m_children = rhs.m_children;
@@ -2573,11 +2640,14 @@ public:
SetRowIndex(row_idx);
++row_idx;
- // The root item must calculate its children
- if (m_parent == NULL)
+ const bool expanded = IsExpanded();
+
+ // The root item must calculate its children,
+ // or we must calculate the number of children
+ // if the item is expanded
+ if (m_parent == NULL || expanded)
GetNumChildren();
- const bool expanded = IsExpanded();
for (auto &item : m_children)
{
if (expanded)
@@ -2650,7 +2720,8 @@ public:
window.PutChar (ACS_DIAMOND);
window.PutChar (ACS_HLINE);
}
- bool highlight = (selected_row_idx == m_row_idx) && window.IsActive();
+ bool highlight =
+ (selected_row_idx == static_cast<size_t>(m_row_idx)) && window.IsActive();
if (highlight)
window.AttributeOn(A_REVERSE);
@@ -2717,11 +2788,11 @@ public:
TreeItem *
GetItemForRowIndex (uint32_t row_idx)
{
- if (m_row_idx == row_idx)
+ if (static_cast<uint32_t>(m_row_idx) == row_idx)
return this;
if (m_children.empty())
return NULL;
- if (m_children.back().m_row_idx < row_idx)
+ if (static_cast<uint32_t>(m_children.back().m_row_idx) < row_idx)
return NULL;
if (IsExpanded())
{
@@ -2735,17 +2806,18 @@ public:
return NULL;
}
-// void *
-// GetUserData() const
-// {
-// return m_user_data;
-// }
-//
-// void
-// SetUserData (void *user_data)
-// {
-// m_user_data = user_data;
-// }
+ void *
+ GetUserData() const
+ {
+ return m_user_data;
+ }
+
+ void
+ SetUserData (void *user_data)
+ {
+ m_user_data = user_data;
+ }
+
uint64_t
GetIdentifier() const
{
@@ -2759,10 +2831,16 @@ public:
}
+ void
+ SetMightHaveChildren (bool b)
+ {
+ m_might_have_children = b;
+ }
+
protected:
TreeItem *m_parent;
TreeDelegate &m_delegate;
- //void *m_user_data;
+ void *m_user_data;
uint64_t m_identifier;
int m_row_idx; // Zero based visible row index, -1 if not visible or for the root item
std::vector<TreeItem> m_children;
@@ -3004,12 +3082,9 @@ protected:
class FrameTreeDelegate : public TreeDelegate
{
public:
- FrameTreeDelegate (const ThreadSP &thread_sp) :
- TreeDelegate(),
- m_thread_wp()
+ FrameTreeDelegate () :
+ TreeDelegate()
{
- if (thread_sp)
- m_thread_wp = thread_sp;
}
virtual ~FrameTreeDelegate()
@@ -3019,11 +3094,11 @@ public:
virtual void
TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
{
- ThreadSP thread_sp = m_thread_wp.lock();
- if (thread_sp)
+ Thread* thread = (Thread*)item.GetUserData();
+ if (thread)
{
const uint64_t frame_idx = item.GetIdentifier();
- StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(frame_idx);
+ StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_idx);
if (frame_sp)
{
StreamString strm;
@@ -3048,23 +3123,16 @@ public:
virtual bool
TreeDelegateItemSelected (TreeItem &item)
{
- ThreadSP thread_sp = m_thread_wp.lock();
- if (thread_sp)
+ Thread* thread = (Thread*)item.GetUserData();
+ if (thread)
{
+ thread->GetProcess()->GetThreadList().SetSelectedThreadByID(thread->GetID());
const uint64_t frame_idx = item.GetIdentifier();
- thread_sp->SetSelectedFrameByIndex(frame_idx);
+ thread->SetSelectedFrameByIndex(frame_idx);
return true;
}
return false;
}
- void
- SetThread (ThreadSP thread_sp)
- {
- m_thread_wp = thread_sp;
- }
-
-protected:
- ThreadWP m_thread_wp;
};
class ThreadTreeDelegate : public TreeDelegate
@@ -3073,7 +3141,6 @@ public:
ThreadTreeDelegate (Debugger &debugger) :
TreeDelegate(),
m_debugger (debugger),
- m_thread_wp (),
m_tid (LLDB_INVALID_THREAD_ID),
m_stop_id (UINT32_MAX)
{
@@ -3084,10 +3151,25 @@ public:
{
}
+ ProcessSP
+ GetProcess ()
+ {
+ return m_debugger.GetCommandInterpreter().GetExecutionContext().GetProcessSP();
+ }
+
+ ThreadSP
+ GetThread (const TreeItem &item)
+ {
+ ProcessSP process_sp = GetProcess ();
+ if (process_sp)
+ return process_sp->GetThreadList().FindThreadByID(item.GetIdentifier());
+ return ThreadSP();
+ }
+
virtual void
TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
{
- ThreadSP thread_sp = m_thread_wp.lock();
+ ThreadSP thread_sp = GetThread (item);
if (thread_sp)
{
StreamString strm;
@@ -3103,43 +3185,36 @@ public:
virtual void
TreeDelegateGenerateChildren (TreeItem &item)
{
- TargetSP target_sp (m_debugger.GetSelectedTarget());
- if (target_sp)
+ ProcessSP process_sp = GetProcess ();
+ if (process_sp && process_sp->IsAlive())
{
- ProcessSP process_sp = target_sp->GetProcessSP();
- if (process_sp && process_sp->IsAlive())
+ StateType state = process_sp->GetState();
+ if (StateIsStoppedState(state, true))
{
- StateType state = process_sp->GetState();
- if (StateIsStoppedState(state, true))
+ ThreadSP thread_sp = GetThread (item);
+ if (thread_sp)
{
- ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread();
- if (thread_sp)
+ if (m_stop_id == process_sp->GetStopID() && thread_sp->GetID() == m_tid)
+ return; // Children are already up to date
+ if (!m_frame_delegate_sp)
{
- if (m_stop_id == process_sp->GetStopID() && thread_sp->GetID() == m_tid)
- return; // Children are already up to date
- if (m_frame_delegate_sp)
- m_frame_delegate_sp->SetThread(thread_sp);
- else
- {
- // Always expand the thread item the first time we show it
- item.Expand();
- m_frame_delegate_sp.reset (new FrameTreeDelegate(thread_sp));
- }
+ // Always expand the thread item the first time we show it
+ m_frame_delegate_sp.reset (new FrameTreeDelegate());
+ }
- m_stop_id = process_sp->GetStopID();
- m_thread_wp = thread_sp;
- m_tid = thread_sp->GetID();
-
- TreeItem t (&item, *m_frame_delegate_sp, false);
- size_t num_frames = thread_sp->GetStackFrameCount();
- item.Resize (num_frames, t);
- for (size_t i=0; i<num_frames; ++i)
- {
- item[i].SetIdentifier(i);
- }
+ m_stop_id = process_sp->GetStopID();
+ m_tid = thread_sp->GetID();
+
+ TreeItem t (&item, *m_frame_delegate_sp, false);
+ size_t num_frames = thread_sp->GetStackFrameCount();
+ item.Resize (num_frames, t);
+ for (size_t i=0; i<num_frames; ++i)
+ {
+ item[i].SetUserData(thread_sp.get());
+ item[i].SetIdentifier(i);
}
- return;
}
+ return;
}
}
item.ClearChildren();
@@ -3148,16 +3223,24 @@ public:
virtual bool
TreeDelegateItemSelected (TreeItem &item)
{
- ThreadSP thread_sp = m_thread_wp.lock();
- if (thread_sp)
+ ProcessSP process_sp = GetProcess ();
+ if (process_sp && process_sp->IsAlive())
{
- ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList();
- Mutex::Locker locker (thread_list.GetMutex());
- ThreadSP selected_thread_sp = thread_list.GetSelectedThread();
- if (selected_thread_sp->GetID() != thread_sp->GetID())
+ StateType state = process_sp->GetState();
+ if (StateIsStoppedState(state, true))
{
- thread_list.SetSelectedThreadByID(thread_sp->GetID());
- return true;
+ ThreadSP thread_sp = GetThread (item);
+ if (thread_sp)
+ {
+ ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList();
+ Mutex::Locker locker (thread_list.GetMutex());
+ ThreadSP selected_thread_sp = thread_list.GetSelectedThread();
+ if (selected_thread_sp->GetID() != thread_sp->GetID())
+ {
+ thread_list.SetSelectedThreadByID(thread_sp->GetID());
+ return true;
+ }
+ }
}
}
return false;
@@ -3165,12 +3248,100 @@ public:
protected:
Debugger &m_debugger;
- ThreadWP m_thread_wp;
std::shared_ptr<FrameTreeDelegate> m_frame_delegate_sp;
lldb::user_id_t m_tid;
uint32_t m_stop_id;
};
+class ThreadsTreeDelegate : public TreeDelegate
+{
+public:
+ ThreadsTreeDelegate (Debugger &debugger) :
+ TreeDelegate(),
+ m_thread_delegate_sp (),
+ m_debugger (debugger),
+ m_stop_id (UINT32_MAX)
+ {
+ }
+
+ virtual
+ ~ThreadsTreeDelegate()
+ {
+ }
+
+ ProcessSP
+ GetProcess ()
+ {
+ return m_debugger.GetCommandInterpreter().GetExecutionContext().GetProcessSP();
+ }
+
+ virtual void
+ TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
+ {
+ ProcessSP process_sp = GetProcess ();
+ if (process_sp && process_sp->IsAlive())
+ {
+ StreamString strm;
+ ExecutionContext exe_ctx (process_sp);
+ const char *format = "process ${process.id}{, name = ${process.name}}";
+ if (Debugger::FormatPrompt (format, NULL, &exe_ctx, NULL, strm))
+ {
+ int right_pad = 1;
+ window.PutCStringTruncated(strm.GetString().c_str(), right_pad);
+ }
+ }
+ }
+
+ virtual void
+ TreeDelegateGenerateChildren (TreeItem &item)
+ {
+ ProcessSP process_sp = GetProcess ();
+ if (process_sp && process_sp->IsAlive())
+ {
+ StateType state = process_sp->GetState();
+ if (StateIsStoppedState(state, true))
+ {
+ const uint32_t stop_id = process_sp->GetStopID();
+ if (m_stop_id == stop_id)
+ return; // Children are already up to date
+
+ m_stop_id = stop_id;
+
+ if (!m_thread_delegate_sp)
+ {
+ // Always expand the thread item the first time we show it
+ //item.Expand();
+ m_thread_delegate_sp.reset (new ThreadTreeDelegate(m_debugger));
+ }
+
+ TreeItem t (&item, *m_thread_delegate_sp, false);
+ ThreadList &threads = process_sp->GetThreadList();
+ Mutex::Locker locker (threads.GetMutex());
+ size_t num_threads = threads.GetSize();
+ item.Resize (num_threads, t);
+ for (size_t i=0; i<num_threads; ++i)
+ {
+ item[i].SetIdentifier(threads.GetThreadAtIndex(i)->GetID());
+ item[i].SetMightHaveChildren(true);
+ }
+ return;
+ }
+ }
+ item.ClearChildren();
+ }
+
+ virtual bool
+ TreeDelegateItemSelected (TreeItem &item)
+ {
+ return false;
+ }
+
+protected:
+ std::shared_ptr<ThreadTreeDelegate> m_thread_delegate_sp;
+ Debugger &m_debugger;
+ uint32_t m_stop_id;
+};
+
class ValueObjectListDelegate : public WindowDelegate
{
public:
@@ -3330,7 +3501,7 @@ public:
// Page up key
if (m_first_visible_row > 0)
{
- if (m_first_visible_row > m_max_y)
+ if (static_cast<int>(m_first_visible_row) > m_max_y)
m_first_visible_row -= m_max_y;
else
m_first_visible_row = 0;
@@ -3341,7 +3512,7 @@ public:
case '.':
case KEY_NPAGE:
// Page down key
- if (m_num_rows > m_max_y)
+ if (m_num_rows > static_cast<size_t>(m_max_y))
{
if (m_first_visible_row + m_max_y < m_num_rows)
{
@@ -3508,7 +3679,7 @@ protected:
// Save the row index in each Row structure
row.row_idx = m_num_rows;
if ((m_num_rows >= m_first_visible_row) &&
- ((m_num_rows - m_first_visible_row) < NumVisibleRows()))
+ ((m_num_rows - m_first_visible_row) < static_cast<size_t>(NumVisibleRows())))
{
row.x = m_min_x;
row.y = m_num_rows - m_first_visible_row + 1;
@@ -3880,7 +4051,7 @@ HelpDialogDelegate::WindowDelegateDraw (Window &window, bool force)
int y = 1;
const int min_y = y;
const int max_y = window_height - 1 - y;
- const int num_visible_lines = max_y - min_y + 1;
+ const size_t num_visible_lines = max_y - min_y + 1;
const size_t num_lines = m_text.GetSize();
const char *bottom_message;
if (num_lines <= num_visible_lines)
@@ -3928,7 +4099,7 @@ HelpDialogDelegate::WindowDelegateHandleChar (Window &window, int key)
case ',':
if (m_first_visible_line > 0)
{
- if (m_first_visible_line >= num_visible_lines)
+ if (static_cast<size_t>(m_first_visible_line) >= num_visible_lines)
m_first_visible_line -= num_visible_lines;
else
m_first_visible_line = 0;
@@ -3939,7 +4110,7 @@ HelpDialogDelegate::WindowDelegateHandleChar (Window &window, int key)
if (m_first_visible_line + num_visible_lines < num_lines)
{
m_first_visible_line += num_visible_lines;
- if (m_first_visible_line > num_lines)
+ if (static_cast<size_t>(m_first_visible_line) > num_lines)
m_first_visible_line = num_lines - num_visible_lines;
}
break;
@@ -4071,7 +4242,7 @@ public:
{
Process *process = exe_ctx.GetProcessPtr();
if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
- exe_ctx.GetThreadRef().StepIn(true, true);
+ exe_ctx.GetThreadRef().StepIn(true);
}
}
return MenuActionResult::Handled;
@@ -4355,9 +4526,13 @@ public:
if (StateIsStoppedState(state, true))
{
- window.MoveCursor (40, 0);
- if (thread)
- window.Printf ("Thread: 0x%4.4" PRIx64, thread->GetID());
+ StreamString strm;
+ const char *format = "Thread: ${thread.id%tid}";
+ if (thread && Debugger::FormatPrompt (format, NULL, &exe_ctx, NULL, strm))
+ {
+ window.MoveCursor (40, 0);
+ window.PutCStringTruncated(strm.GetString().c_str(), 1);
+ }
window.MoveCursor (60, 0);
if (frame)
@@ -4392,6 +4567,7 @@ public:
m_disassembly_scope (NULL),
m_disassembly_sp (),
m_disassembly_range (),
+ m_title (),
m_line_width (4),
m_selected_line (0),
m_pc_line (0),
@@ -4404,31 +4580,30 @@ public:
m_max_y (0)
{
}
-
-
+
virtual
~SourceFileWindowDelegate()
{
}
-
+
void
Update (const SymbolContext &sc)
{
m_sc = sc;
}
-
+
uint32_t
NumVisibleLines () const
{
return m_max_y - m_min_y;
}
-
+
virtual const char *
WindowDelegateGetHelpText ()
{
return "Source/Disassembly window keyboard shortcuts:";
}
-
+
virtual KeyHelp *
WindowDelegateGetKeyHelp ()
{
@@ -4455,7 +4630,7 @@ public:
};
return g_source_view_key_help;
}
-
+
virtual bool
WindowDelegateDraw (Window &window, bool force)
{
@@ -4473,20 +4648,18 @@ public:
update_location = true;
}
}
-
+
m_min_x = 1;
- m_min_y = 1;
+ m_min_y = 2;
m_max_x = window.GetMaxX()-1;
m_max_y = window.GetMaxY()-1;
-
+
const uint32_t num_visible_lines = NumVisibleLines();
StackFrameSP frame_sp;
bool set_selected_line_to_pc = false;
-
if (update_location)
{
-
const bool process_alive = process ? process->IsAlive() : false;
bool thread_changed = false;
if (process_alive)
@@ -4512,9 +4685,17 @@ public:
const bool stop_id_changed = stop_id != m_stop_id;
bool frame_changed = false;
m_stop_id = stop_id;
+ m_title.Clear();
if (frame_sp)
{
m_sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
+ if (m_sc.module_sp)
+ {
+ m_title.Printf("%s", m_sc.module_sp->GetFileSpec().GetFilename().GetCString());
+ ConstString func_name = m_sc.GetFunctionName();
+ if (func_name)
+ m_title.Printf("`%s", func_name.GetCString());
+ }
const uint32_t frame_idx = frame_sp->GetFrameIndex();
frame_changed = frame_idx != m_frame_idx;
m_frame_idx = frame_idx;
@@ -4525,9 +4706,9 @@ public:
frame_changed = m_frame_idx != UINT32_MAX;
m_frame_idx = UINT32_MAX;
}
-
+
const bool context_changed = thread_changed || frame_changed || stop_id_changed;
-
+
if (process_alive)
{
if (m_sc.line_entry.IsValid())
@@ -4543,7 +4724,7 @@ public:
{
// Same file, nothing to do, we should either have the
// lines or not (source file missing)
- if (m_selected_line >= m_first_visible_line)
+ if (m_selected_line >= static_cast<size_t>(m_first_visible_line))
{
if (m_selected_line >= m_first_visible_line + num_visible_lines)
m_first_visible_line = m_selected_line - 10;
@@ -4567,7 +4748,7 @@ public:
int m_line_width = 1;
for (size_t n = num_lines; n >= 10; n = n / 10)
++m_line_width;
-
+
snprintf (m_line_format, sizeof(m_line_format), " %%%iu ", m_line_width);
if (num_lines < num_visible_lines || m_selected_line < num_visible_lines)
m_first_visible_line = 0;
@@ -4580,7 +4761,7 @@ public:
{
m_file_sp.reset();
}
-
+
if (!m_file_sp || m_file_sp->GetNumLines() == 0)
{
// Show disassembly
@@ -4635,11 +4816,23 @@ public:
m_pc_line = UINT32_MAX;
}
}
-
-
+
+ const int window_width = window.GetWidth();
window.Erase();
window.DrawTitleBox ("Sources");
-
+ if (!m_title.GetString().empty())
+ {
+ window.AttributeOn(A_REVERSE);
+ window.MoveCursor(1, 1);
+ window.PutChar(' ');
+ window.PutCStringTruncated(m_title.GetString().c_str(), 1);
+ int x = window.GetCursorX();
+ if (x < window_width - 1)
+ {
+ window.Printf ("%*s", window_width - x - 1, "");
+ }
+ window.AttributeOff(A_REVERSE);
+ }
Target *target = exe_ctx.GetTargetPtr();
const size_t num_source_lines = GetNumSourceLines();
@@ -4669,17 +4862,16 @@ public:
}
}
}
-
-
+
const attr_t selected_highlight_attr = A_REVERSE;
const attr_t pc_highlight_attr = COLOR_PAIR(1);
- for (int i=0; i<num_visible_lines; ++i)
+ for (size_t i=0; i<num_visible_lines; ++i)
{
const uint32_t curr_line = m_first_visible_line + i;
if (curr_line < num_source_lines)
{
- const int line_y = 1+i;
+ const int line_y = m_min_y+i;
window.MoveCursor(1, line_y);
const bool is_pc_line = curr_line == m_pc_line;
const bool line_is_selected = m_selected_line == curr_line;
@@ -4691,13 +4883,13 @@ public:
highlight_attr = pc_highlight_attr;
else if (line_is_selected)
highlight_attr = selected_highlight_attr;
-
+
if (bp_lines.find(curr_line+1) != bp_lines.end())
bp_attr = COLOR_PAIR(2);
if (bp_attr)
window.AttributeOn(bp_attr);
-
+
window.Printf (m_line_format, curr_line + 1);
if (bp_attr)
@@ -4709,7 +4901,7 @@ public:
window.PutChar(ACS_DIAMOND);
else
window.PutChar(' ');
-
+
if (highlight_attr)
window.AttributeOn(highlight_attr);
const uint32_t line_len = m_file_sp->GetLineLength(curr_line + 1, false);
@@ -4727,15 +4919,15 @@ public:
if (stop_description && stop_description[0])
{
size_t stop_description_len = strlen(stop_description);
- int desc_x = window.GetWidth() - stop_description_len - 16;
+ int desc_x = window_width - stop_description_len - 16;
window.Printf ("%*s", desc_x - window.GetCursorX(), "");
- //window.MoveCursor(window.GetWidth() - stop_description_len - 15, line_y);
+ //window.MoveCursor(window_width - stop_description_len - 15, line_y);
window.Printf ("<<< Thread %u: %s ", thread->GetIndexID(), stop_description);
}
}
else
{
- window.Printf ("%*s", window.GetWidth() - window.GetCursorX() - 1, "");
+ window.Printf ("%*s", window_width - window.GetCursorX() - 1, "");
}
}
if (highlight_attr)
@@ -4777,16 +4969,15 @@ public:
}
}
}
-
-
+
const attr_t selected_highlight_attr = A_REVERSE;
const attr_t pc_highlight_attr = COLOR_PAIR(1);
-
+
StreamString strm;
InstructionList &insts = m_disassembly_sp->GetInstructionList();
Address pc_address;
-
+
if (frame_sp)
pc_address = frame_sp->GetFrameCodeAddress();
const uint32_t pc_idx = pc_address.IsValid() ? insts.GetIndexOfInstructionAtAddress (pc_address) : UINT32_MAX;
@@ -4796,12 +4987,12 @@ public:
}
const uint32_t non_visible_pc_offset = (num_visible_lines / 5);
- if (m_first_visible_line >= num_disassembly_lines)
+ if (static_cast<size_t>(m_first_visible_line) >= num_disassembly_lines)
m_first_visible_line = 0;
if (pc_idx < num_disassembly_lines)
{
- if (pc_idx < m_first_visible_line ||
+ if (pc_idx < static_cast<uint32_t>(m_first_visible_line) ||
pc_idx >= m_first_visible_line + num_visible_lines)
m_first_visible_line = pc_idx - non_visible_pc_offset;
}
@@ -4812,8 +5003,9 @@ public:
Instruction *inst = insts.GetInstructionAtIndex(inst_idx).get();
if (!inst)
break;
-
- window.MoveCursor(1, i+1);
+
+ const int line_y = m_min_y+i;
+ window.MoveCursor(1, line_y);
const bool is_pc_line = frame_sp && inst_idx == pc_idx;
const bool line_is_selected = m_selected_line == inst_idx;
// Highlight the line as the PC line first, then if the selected line
@@ -4824,28 +5016,29 @@ public:
highlight_attr = pc_highlight_attr;
else if (line_is_selected)
highlight_attr = selected_highlight_attr;
-
+
if (bp_file_addrs.find(inst->GetAddress().GetFileAddress()) != bp_file_addrs.end())
bp_attr = COLOR_PAIR(2);
-
+
if (bp_attr)
window.AttributeOn(bp_attr);
-
- window.Printf (" 0x%16.16llx ", inst->GetAddress().GetLoadAddress(target));
-
+
+ window.Printf (" 0x%16.16llx ",
+ static_cast<unsigned long long>(inst->GetAddress().GetLoadAddress(target)));
+
if (bp_attr)
window.AttributeOff(bp_attr);
-
+
window.PutChar(ACS_VLINE);
// Mark the line with the PC with a diamond
if (is_pc_line)
window.PutChar(ACS_DIAMOND);
else
window.PutChar(' ');
-
+
if (highlight_attr)
window.AttributeOn(highlight_attr);
-
+
const char *mnemonic = inst->GetMnemonic(&exe_ctx);
const char *operands = inst->GetOperands(&exe_ctx);
const char *comment = inst->GetComment(&exe_ctx);
@@ -4856,7 +5049,7 @@ public:
operands = NULL;
if (comment && comment[0] == '\0')
comment = NULL;
-
+
strm.Clear();
if (mnemonic && operands && comment)
@@ -4865,10 +5058,10 @@ public:
strm.Printf ("%-8s %s", mnemonic, operands);
else if (mnemonic)
strm.Printf ("%s", mnemonic);
-
+
int right_pad = 1;
window.PutCStringTruncated(strm.GetString().c_str(), right_pad);
-
+
if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0)
{
StopInfoSP stop_info_sp;
@@ -4880,15 +5073,15 @@ public:
if (stop_description && stop_description[0])
{
size_t stop_description_len = strlen(stop_description);
- int desc_x = window.GetWidth() - stop_description_len - 16;
+ int desc_x = window_width - stop_description_len - 16;
window.Printf ("%*s", desc_x - window.GetCursorX(), "");
- //window.MoveCursor(window.GetWidth() - stop_description_len - 15, line_y);
+ //window.MoveCursor(window_width - stop_description_len - 15, line_y);
window.Printf ("<<< Thread %u: %s ", thread->GetIndexID(), stop_description);
}
}
else
{
- window.Printf ("%*s", window.GetWidth() - window.GetCursorX() - 1, "");
+ window.Printf ("%*s", window_width - window.GetCursorX() - 1, "");
}
}
if (highlight_attr)
@@ -4899,7 +5092,7 @@ public:
window.DeferredRefresh();
return true; // Drawing handled
}
-
+
size_t
GetNumLines ()
{
@@ -4908,7 +5101,7 @@ public:
num_lines = GetNumDisassemblyLines();
return num_lines;
}
-
+
size_t
GetNumSourceLines () const
{
@@ -4935,13 +5128,13 @@ public:
case ',':
case KEY_PPAGE:
// Page up key
- if (m_first_visible_line > num_visible_lines)
+ if (static_cast<uint32_t>(m_first_visible_line) > num_visible_lines)
m_first_visible_line -= num_visible_lines;
else
m_first_visible_line = 0;
m_selected_line = m_first_visible_line;
return eKeyHandled;
-
+
case '.':
case KEY_NPAGE:
// Page down key
@@ -4955,12 +5148,12 @@ public:
m_selected_line = m_first_visible_line;
}
return eKeyHandled;
-
+
case KEY_UP:
if (m_selected_line > 0)
{
m_selected_line--;
- if (m_first_visible_line > m_selected_line)
+ if (static_cast<size_t>(m_first_visible_line) > m_selected_line)
m_first_visible_line = m_selected_line;
}
return eKeyHandled;
@@ -4973,7 +5166,7 @@ public:
m_first_visible_line++;
}
return eKeyHandled;
-
+
case '\r':
case '\n':
case KEY_ENTER:
@@ -5067,7 +5260,7 @@ public:
exe_ctx.GetProcessRef().Resume();
}
return eKeyHandled;
-
+
case 'o':
// 'o' == step out
{
@@ -5096,12 +5289,11 @@ public:
if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true))
{
bool source_step = (c == 's');
- bool avoid_code_without_debug_info = true;
- exe_ctx.GetThreadRef().StepIn(source_step, avoid_code_without_debug_info);
+ exe_ctx.GetThreadRef().StepIn(source_step);
}
}
return eKeyHandled;
-
+
case 'h':
window.CreateHelpSubwindow ();
return eKeyHandled;
@@ -5111,7 +5303,7 @@ public:
}
return eKeyNotHandled;
}
-
+
protected:
typedef std::set<uint32_t> BreakpointLines;
typedef std::set<lldb::addr_t> BreakpointAddrs;
@@ -5122,6 +5314,7 @@ protected:
SymbolContextScope *m_disassembly_scope;
lldb::DisassemblerSP m_disassembly_sp;
AddressRange m_disassembly_range;
+ StreamString m_title;
lldb::user_id_t m_tid;
char m_line_format[8];
int m_line_width;
@@ -5235,7 +5428,7 @@ IOHandlerCursesGUI::Activate ()
main_window_sp->SetDelegate (std::static_pointer_cast<WindowDelegate>(app_delegate_sp));
source_window_sp->SetDelegate (WindowDelegateSP(new SourceFileWindowDelegate(m_debugger)));
variables_window_sp->SetDelegate (WindowDelegateSP(new FrameVariablesWindowDelegate(m_debugger)));
- TreeDelegateSP thread_delegate_sp (new ThreadTreeDelegate(m_debugger));
+ TreeDelegateSP thread_delegate_sp (new ThreadsTreeDelegate(m_debugger));
threads_window_sp->SetDelegate (WindowDelegateSP(new TreeWindowDelegate(m_debugger, thread_delegate_sp)));
status_window_sp->SetDelegate (WindowDelegateSP(new StatusBarWindowDelegate(m_debugger)));
@@ -5291,9 +5484,10 @@ IOHandlerCursesGUI::Cancel ()
{
}
-void
+bool
IOHandlerCursesGUI::Interrupt ()
{
+ return false;
}
@@ -5302,4 +5496,4 @@ IOHandlerCursesGUI::GotEOF()
{
}
-#endif // #ifndef LLDB_DISABLE_CURSES \ No newline at end of file
+#endif // #ifndef LLDB_DISABLE_CURSES
diff --git a/source/Core/Language.cpp b/source/Core/Language.cpp
index af62af37da0d..1ffd5aadc526 100644
--- a/source/Core/Language.cpp
+++ b/source/Core/Language.cpp
@@ -10,6 +10,7 @@
#include "lldb/lldb-private.h"
#include "lldb/Core/Language.h"
#include "lldb/Core/Stream.h"
+#include "llvm/ADT/STLExtras.h"
#include <string.h>
using namespace lldb;
@@ -48,8 +49,7 @@ g_languages[] =
{ { "python" , NULL , "Python" } }
};
-static const size_t
-g_num_languages = sizeof(g_languages)/sizeof(LanguageStrings);
+static const size_t g_num_languages = llvm::array_lengthof(g_languages);
Language::Language(LanguageType language) :
m_language (language)
diff --git a/source/Core/Listener.cpp b/source/Core/Listener.cpp
index aca2b374092e..f71d766e0a1c 100644
--- a/source/Core/Listener.cpp
+++ b/source/Core/Listener.cpp
@@ -34,21 +34,23 @@ Listener::Listener(const char *name) :
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Listener::Listener('%s')", this, m_name.c_str());
+ log->Printf ("%p Listener::Listener('%s')",
+ static_cast<void*>(this), m_name.c_str());
}
Listener::~Listener()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
Mutex::Locker locker (m_broadcasters_mutex);
-
+
size_t num_managers = m_broadcaster_managers.size();
-
+
for (size_t i = 0; i < num_managers; i++)
m_broadcaster_managers[i]->RemoveListener(*this);
-
+
if (log)
- log->Printf ("%p Listener::~Listener('%s')", this, m_name.c_str());
+ log->Printf ("%p Listener::~Listener('%s')",
+ static_cast<void*>(this), m_name.c_str());
Clear();
}
@@ -87,11 +89,9 @@ Listener::StartListeningForEvents (Broadcaster* broadcaster, uint32_t event_mask
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS));
if (log)
log->Printf ("%p Listener::StartListeningForEvents (broadcaster = %p, mask = 0x%8.8x) acquired_mask = 0x%8.8x for %s",
- this,
- broadcaster,
- event_mask,
- acquired_mask,
- m_name.c_str());
+ static_cast<void*>(this),
+ static_cast<void*>(broadcaster), event_mask,
+ acquired_mask, m_name.c_str());
return acquired_mask;
@@ -115,8 +115,14 @@ Listener::StartListeningForEvents (Broadcaster* broadcaster, uint32_t event_mask
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS));
if (log)
+ {
+ void **pointer = reinterpret_cast<void**>(&callback);
log->Printf ("%p Listener::StartListeningForEvents (broadcaster = %p, mask = 0x%8.8x, callback = %p, user_data = %p) acquired_mask = 0x%8.8x for %s",
- this, broadcaster, event_mask, callback, callback_user_data, acquired_mask, m_name.c_str());
+ static_cast<void*>(this),
+ static_cast<void*>(broadcaster), event_mask, *pointer,
+ static_cast<void*>(callback_user_data), acquired_mask,
+ m_name.c_str());
+ }
return acquired_mask;
}
@@ -140,7 +146,7 @@ Listener::StopListeningForEvents (Broadcaster* broadcaster, uint32_t event_mask)
return false;
}
-// Called when a Broadcaster is in its destuctor. We need to remove all
+// Called when a Broadcaster is in its destructor. We need to remove all
// knowledge of this broadcaster and any events that it may have queued up
void
Listener::BroadcasterWillDestruct (Broadcaster *broadcaster)
@@ -185,7 +191,9 @@ Listener::AddEvent (EventSP &event_sp)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS));
if (log)
- log->Printf ("%p Listener('%s')::AddEvent (event_sp = {%p})", this, m_name.c_str(), event_sp.get());
+ log->Printf ("%p Listener('%s')::AddEvent (event_sp = {%p})",
+ static_cast<void*>(this), m_name.c_str(),
+ static_cast<void*>(event_sp.get()));
// Scope for "locker"
{
@@ -292,17 +300,14 @@ Listener::FindNextEventInternal
if (pos != m_events.end())
{
event_sp = *pos;
-
+
if (log)
log->Printf ("%p '%s' Listener::FindNextEventInternal(broadcaster=%p, broadcaster_names=%p[%u], event_type_mask=0x%8.8x, remove=%i) event %p",
- this,
- GetName(),
- broadcaster,
- broadcaster_names,
- num_broadcaster_names,
- event_type_mask,
- remove,
- event_sp.get());
+ static_cast<void*>(this), GetName(),
+ static_cast<void*>(broadcaster),
+ static_cast<const void*>(broadcaster_names),
+ num_broadcaster_names, event_type_mask, remove,
+ static_cast<void*>(event_sp.get()));
if (remove)
{
@@ -311,16 +316,16 @@ Listener::FindNextEventInternal
if (m_events.empty())
m_cond_wait.SetValue (false, eBroadcastNever);
}
-
+
// Unlock the event queue here. We've removed this event and are about to return
// it so it should be okay to get the next event off the queue here - and it might
// be useful to do that in the "DoOnRemoval".
lock.Unlock();
-
+
// Don't call DoOnRemoval if you aren't removing the event...
if (remove)
event_sp->DoOnRemoval();
-
+
return true;
}
@@ -404,10 +409,9 @@ Listener::WaitForEventsInternal
bool timed_out = false;
if (log)
- {
log->Printf ("%p Listener::WaitForEventsInternal (timeout = { %p }) for %s",
- this, timeout, m_name.c_str());
- }
+ static_cast<void*>(this), static_cast<const void*>(timeout),
+ m_name.c_str());
while (1)
{
@@ -421,7 +425,7 @@ Listener::WaitForEventsInternal
// added that might meet our current filter
// But first poll for any new event that might satisfy our condition, and if so consume it,
// otherwise wait.
-
+
Mutex::Locker event_locker(m_events_mutex);
const bool remove = false;
if (FindNextEventInternal (broadcaster, broadcaster_names, num_broadcaster_names, event_type_mask, event_sp, remove))
@@ -437,14 +441,16 @@ Listener::WaitForEventsInternal
{
log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS);
if (log)
- log->Printf ("%p Listener::WaitForEventsInternal() timed out for %s", this, m_name.c_str());
+ log->Printf ("%p Listener::WaitForEventsInternal() timed out for %s",
+ static_cast<void*>(this), m_name.c_str());
break;
}
else
{
log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS);
if (log)
- log->Printf ("%p Listener::WaitForEventsInternal() unknown error for %s", this, m_name.c_str());
+ log->Printf ("%p Listener::WaitForEventsInternal() unknown error for %s",
+ static_cast<void*>(this), m_name.c_str());
break;
}
}
diff --git a/source/Core/Log.cpp b/source/Core/Log.cpp
index b7dc056af6ce..3adca6e5385c 100644
--- a/source/Core/Log.cpp
+++ b/source/Core/Log.cpp
@@ -110,7 +110,7 @@ Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args)
if (m_options.Test (LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD))
header.Printf ("[%4.4x/%4.4" PRIx64 "]: ", getpid(), Host::GetCurrentThreadID());
- // Add the process and thread if requested
+ // Add the thread name if requested
if (m_options.Test (LLDB_LOG_OPTION_PREPEND_THREAD_NAME))
{
std::string thread_name (Host::GetThreadName (getpid(), Host::GetCurrentThreadID()));
diff --git a/source/Core/Mangled.cpp b/source/Core/Mangled.cpp
index 55bd3cbb8e99..c4fa10fedd86 100644
--- a/source/Core/Mangled.cpp
+++ b/source/Core/Mangled.cpp
@@ -20,6 +20,14 @@
#ifdef LLDB_USE_BUILTIN_DEMANGLER
+// Provide a fast-path demangler implemented in FastDemangle.cpp until it can
+// replace the existing C++ demangler with a complete implementation
+namespace lldb_private
+{
+ extern char * FastDemangle (const char * mangled_name,
+ long mangled_name_length);
+}
+
//----------------------------------------------------------------------
// Inlined copy of:
// http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp
@@ -3932,15 +3940,15 @@ parse_nested_name(const char* first, const char* last, C& db)
const char* t0 = parse_cv_qualifiers(first+1, last, cv);
if (t0 == last)
return first;
- db.ref = 0;
+ unsigned ref = 0;
if (*t0 == 'R')
{
- db.ref = 1;
+ ref = 1;
++t0;
}
else if (*t0 == 'O')
{
- db.ref = 2;
+ ref = 2;
++t0;
}
db.names.emplace_back();
@@ -4054,6 +4062,7 @@ parse_nested_name(const char* first, const char* last, C& db)
}
}
first = t0 + 1;
+ db.ref = ref;
db.cv = cv;
if (pop_subs && !db.subs.empty())
db.subs.pop_back();
@@ -4413,7 +4422,7 @@ parse_special_name(const char* first, const char* last, C& db)
{
if (db.names.empty())
return first;
- if (first[2] == 'v')
+ if (first[1] == 'v')
{
db.names.back().first.insert(0, "virtual thunk to ");
first = t;
@@ -5128,7 +5137,6 @@ Mangled::SetValue (const ConstString &name)
}
}
-
//----------------------------------------------------------------------
// Generate the demangled name on demand using this accessor. Code in
// this class will need to use this accessor if it wishes to decode
@@ -5157,7 +5165,13 @@ Mangled::GetDemangledName () const
// We didn't already mangle this name, demangle it and if all goes well
// add it to our map.
#ifdef LLDB_USE_BUILTIN_DEMANGLER
- char *demangled_name = __cxa_demangle (mangled_cstr, NULL, NULL, NULL);
+ // Try to use the fast-path demangler first for the
+ // performance win, falling back to the full demangler only
+ // when necessary
+ char *demangled_name = FastDemangle (mangled_cstr,
+ m_mangled.GetLength());
+ if (!demangled_name)
+ demangled_name = __cxa_demangle (mangled_cstr, NULL, NULL, NULL);
#elif defined(_MSC_VER)
// Cannot demangle on msvc.
char *demangled_name = nullptr;
@@ -5242,7 +5256,8 @@ Mangled::Dump (Stream *s) const
void
Mangled::DumpDebug (Stream *s) const
{
- s->Printf("%*p: Mangled mangled = ", (int)sizeof(void*) * 2, this);
+ s->Printf("%*p: Mangled mangled = ", static_cast<int>(sizeof(void*) * 2),
+ static_cast<const void*>(this));
m_mangled.DumpDebug(s);
s->Printf(", demangled = ");
m_demangled.DumpDebug(s);
diff --git a/source/Core/Module.cpp b/source/Core/Module.cpp
index d5758c09b1e2..6f16ada49824 100644
--- a/source/Core/Module.cpp
+++ b/source/Core/Module.cpp
@@ -37,6 +37,8 @@
#include "lldb/Target/Target.h"
#include "lldb/Symbol/SymbolFile.h"
+#include "Plugins/ObjectFile/JIT/ObjectFileJIT.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -131,20 +133,21 @@ namespace lldb {
Module::Module (const ModuleSpec &module_spec) :
m_mutex (Mutex::eMutexTypeRecursive),
- m_mod_time (module_spec.GetFileSpec().GetModificationTime()),
- m_arch (module_spec.GetArchitecture()),
+ m_mod_time (),
+ m_arch (),
m_uuid (),
- m_file (module_spec.GetFileSpec()),
- m_platform_file(module_spec.GetPlatformFileSpec()),
+ m_file (),
+ m_platform_file(),
m_remote_install_file(),
- m_symfile_spec (module_spec.GetSymbolFileSpec()),
- m_object_name (module_spec.GetObjectName()),
- m_object_offset (module_spec.GetObjectOffset()),
- m_object_mod_time (module_spec.GetObjectModificationTime()),
+ m_symfile_spec (),
+ m_object_name (),
+ m_object_offset (),
+ m_object_mod_time (),
m_objfile_sp (),
m_symfile_ap (),
m_ast (),
m_source_mappings (),
+ m_sections_ap(),
m_did_load_objfile (false),
m_did_load_symbol_vendor (false),
m_did_parse_uuid (false),
@@ -158,22 +161,81 @@ Module::Module (const ModuleSpec &module_spec) :
Mutex::Locker locker (GetAllocationModuleCollectionMutex());
GetModuleCollection().push_back(this);
}
-
+
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT|LIBLLDB_LOG_MODULES));
if (log)
log->Printf ("%p Module::Module((%s) '%s%s%s%s')",
- this,
- m_arch.GetArchitectureName(),
- m_file.GetPath().c_str(),
- m_object_name.IsEmpty() ? "" : "(",
- m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
- m_object_name.IsEmpty() ? "" : ")");
+ static_cast<void*>(this),
+ module_spec.GetArchitecture().GetArchitectureName(),
+ module_spec.GetFileSpec().GetPath().c_str(),
+ module_spec.GetObjectName().IsEmpty() ? "" : "(",
+ module_spec.GetObjectName().IsEmpty() ? "" : module_spec.GetObjectName().AsCString(""),
+ module_spec.GetObjectName().IsEmpty() ? "" : ")");
+
+ // First extract all module specifications from the file using the local
+ // file path. If there are no specifications, then don't fill anything in
+ ModuleSpecList modules_specs;
+ if (ObjectFile::GetModuleSpecifications(module_spec.GetFileSpec(), 0, 0, modules_specs) == 0)
+ return;
+
+ // Now make sure that one of the module specifications matches what we just
+ // extract. We might have a module specification that specifies a file "/usr/lib/dyld"
+ // with UUID XXX, but we might have a local version of "/usr/lib/dyld" that has
+ // UUID YYY and we don't want those to match. If they don't match, just don't
+ // fill any ivars in so we don't accidentally grab the wrong file later since
+ // they don't match...
+ ModuleSpec matching_module_spec;
+ if (modules_specs.FindMatchingModuleSpec(module_spec, matching_module_spec) == 0)
+ return;
+
+ if (module_spec.GetFileSpec())
+ m_mod_time = module_spec.GetFileSpec().GetModificationTime();
+ else if (matching_module_spec.GetFileSpec())
+ m_mod_time = matching_module_spec.GetFileSpec().GetModificationTime();
+
+ // Copy the architecture from the actual spec if we got one back, else use the one that was specified
+ if (matching_module_spec.GetArchitecture().IsValid())
+ m_arch = matching_module_spec.GetArchitecture();
+ else if (module_spec.GetArchitecture().IsValid())
+ m_arch = module_spec.GetArchitecture();
+
+ // Copy the file spec over and use the specified one (if there was one) so we
+ // don't use a path that might have gotten resolved a path in 'matching_module_spec'
+ if (module_spec.GetFileSpec())
+ m_file = module_spec.GetFileSpec();
+ else if (matching_module_spec.GetFileSpec())
+ m_file = matching_module_spec.GetFileSpec();
+
+ // Copy the platform file spec over
+ if (module_spec.GetPlatformFileSpec())
+ m_platform_file = module_spec.GetPlatformFileSpec();
+ else if (matching_module_spec.GetPlatformFileSpec())
+ m_platform_file = matching_module_spec.GetPlatformFileSpec();
+
+ // Copy the symbol file spec over
+ if (module_spec.GetSymbolFileSpec())
+ m_symfile_spec = module_spec.GetSymbolFileSpec();
+ else if (matching_module_spec.GetSymbolFileSpec())
+ m_symfile_spec = matching_module_spec.GetSymbolFileSpec();
+
+ // Copy the object name over
+ if (matching_module_spec.GetObjectName())
+ m_object_name = matching_module_spec.GetObjectName();
+ else
+ m_object_name = module_spec.GetObjectName();
+
+ // Always trust the object offset (file offset) and object modification
+ // time (for mod time in a BSD static archive) of from the matching
+ // module specification
+ m_object_offset = matching_module_spec.GetObjectOffset();
+ m_object_mod_time = matching_module_spec.GetObjectModificationTime();
+
}
Module::Module(const FileSpec& file_spec,
const ArchSpec& arch,
const ConstString *object_name,
- off_t object_offset,
+ lldb::offset_t object_offset,
const TimeValue *object_mod_time_ptr) :
m_mutex (Mutex::eMutexTypeRecursive),
m_mod_time (file_spec.GetModificationTime()),
@@ -190,6 +252,7 @@ Module::Module(const FileSpec& file_spec,
m_symfile_ap (),
m_ast (),
m_source_mappings (),
+ m_sections_ap(),
m_did_load_objfile (false),
m_did_load_symbol_vendor (false),
m_did_parse_uuid (false),
@@ -206,21 +269,49 @@ Module::Module(const FileSpec& file_spec,
if (object_name)
m_object_name = *object_name;
-
+
if (object_mod_time_ptr)
m_object_mod_time = *object_mod_time_ptr;
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT|LIBLLDB_LOG_MODULES));
if (log)
log->Printf ("%p Module::Module((%s) '%s%s%s%s')",
- this,
- m_arch.GetArchitectureName(),
+ static_cast<void*>(this), m_arch.GetArchitectureName(),
m_file.GetPath().c_str(),
m_object_name.IsEmpty() ? "" : "(",
m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
m_object_name.IsEmpty() ? "" : ")");
}
+Module::Module () :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_mod_time (),
+ m_arch (),
+ m_uuid (),
+ m_file (),
+ m_platform_file(),
+ m_remote_install_file (),
+ m_symfile_spec (),
+ m_object_name (),
+ m_object_offset (0),
+ m_object_mod_time (),
+ m_objfile_sp (),
+ m_symfile_ap (),
+ m_ast (),
+ m_source_mappings (),
+ m_sections_ap(),
+ m_did_load_objfile (false),
+ m_did_load_symbol_vendor (false),
+ m_did_parse_uuid (false),
+ m_did_init_ast (false),
+ m_is_dynamic_loader_module (false),
+ m_file_has_changed (false),
+ m_first_file_changed_log (false)
+{
+ Mutex::Locker locker (GetAllocationModuleCollectionMutex());
+ GetModuleCollection().push_back(this);
+}
+
Module::~Module()
{
// Lock our module down while we tear everything down to make sure
@@ -238,7 +329,7 @@ Module::~Module()
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT|LIBLLDB_LOG_MODULES));
if (log)
log->Printf ("%p Module::~Module((%s) '%s%s%s%s')",
- this,
+ static_cast<void*>(this),
m_arch.GetArchitectureName(),
m_file.GetPath().c_str(),
m_object_name.IsEmpty() ? "" : "(",
@@ -255,7 +346,7 @@ Module::~Module()
}
ObjectFile *
-Module::GetMemoryObjectFile (const lldb::ProcessSP &process_sp, lldb::addr_t header_addr, Error &error)
+Module::GetMemoryObjectFile (const lldb::ProcessSP &process_sp, lldb::addr_t header_addr, Error &error, size_t size_to_read)
{
if (m_objfile_sp)
{
@@ -267,13 +358,13 @@ Module::GetMemoryObjectFile (const lldb::ProcessSP &process_sp, lldb::addr_t hea
if (process_sp)
{
m_did_load_objfile = true;
- std::unique_ptr<DataBufferHeap> data_ap (new DataBufferHeap (512, 0));
+ std::unique_ptr<DataBufferHeap> data_ap (new DataBufferHeap (size_to_read, 0));
Error readmem_error;
const size_t bytes_read = process_sp->ReadMemory (header_addr,
data_ap->GetBytes(),
data_ap->GetByteSize(),
readmem_error);
- if (bytes_read == 512)
+ if (bytes_read == size_to_read)
{
DataBufferSP data_sp(data_ap.release());
m_objfile_sp = ObjectFile::FindPlugin(shared_from_this(), process_sp, header_addr, data_sp);
@@ -342,6 +433,7 @@ Module::GetClangASTContext ()
&& object_arch.GetTriple().getOS() == llvm::Triple::UnknownOS)
{
if (object_arch.GetTriple().getArch() == llvm::Triple::arm ||
+ object_arch.GetTriple().getArch() == llvm::Triple::aarch64 ||
object_arch.GetTriple().getArch() == llvm::Triple::thumb)
{
object_arch.GetTriple().setOS(llvm::Triple::IOS);
@@ -410,14 +502,16 @@ Module::CalculateSymbolContextModule ()
void
Module::DumpSymbolContext(Stream *s)
{
- s->Printf(", Module{%p}", this);
+ s->Printf(", Module{%p}", static_cast<void*>(this));
}
size_t
Module::GetNumCompileUnits()
{
Mutex::Locker locker (m_mutex);
- Timer scoped_timer(__PRETTY_FUNCTION__, "Module::GetNumCompileUnits (module = %p)", this);
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::GetNumCompileUnits (module = %p)",
+ static_cast<void*>(this));
SymbolVendor *symbols = GetSymbolVendor ();
if (symbols)
return symbols->GetNumCompileUnits();
@@ -909,7 +1003,7 @@ Module::FindTypes (const SymbolContext& sc,
// Check if "name" starts with "::" which means the qualified type starts
// from the root namespace and implies and exact match. The typenames we
// get back from clang do not start with "::" so we need to strip this off
- // in order to get the qualfied names to match
+ // in order to get the qualified names to match
if (type_scope.size() >= 2 && type_scope[0] == ':' && type_scope[1] == ':')
{
@@ -930,7 +1024,7 @@ Module::FindTypes (const SymbolContext& sc,
{
// The "type_name_cstr" will have been modified if we have a valid type class
// prefix (like "struct", "class", "union", "typedef" etc).
- num_matches = FindTypes_Impl(sc, ConstString(type_name_cstr), NULL, append, max_matches, types);
+ FindTypes_Impl(sc, ConstString(type_name_cstr), NULL, append, max_matches, types);
types.RemoveMismatchedTypes (type_class);
num_matches = types.GetSize();
}
@@ -1233,6 +1327,17 @@ Module::GetSectionList()
return m_sections_ap.get();
}
+void
+Module::SectionFileAddressesChanged ()
+{
+ ObjectFile *obj_file = GetObjectFile ();
+ if (obj_file)
+ obj_file->SectionFileAddressesChanged ();
+ SymbolVendor* sym_vendor = GetSymbolVendor();
+ if (sym_vendor)
+ sym_vendor->SectionFileAddressesChanged ();
+}
+
SectionList *
Module::GetUnifiedSectionList()
{
@@ -1422,7 +1527,10 @@ Module::LoadScriptingResourceInTarget (Target *target, Error& error, Stream* fee
return false;
}
- LoadScriptFromSymFile shoud_load = target->TargetProperties::GetLoadScriptFromSymbolFile();
+ LoadScriptFromSymFile should_load = target->TargetProperties::GetLoadScriptFromSymbolFile();
+
+ if (should_load == eLoadScriptFromSymFileFalse)
+ return false;
Debugger &debugger = target->GetDebugger();
const ScriptLanguage script_language = debugger.GetScriptLanguage();
@@ -1438,7 +1546,8 @@ Module::LoadScriptingResourceInTarget (Target *target, Error& error, Stream* fee
}
FileSpecList file_specs = platform_sp->LocateExecutableScriptingResources (target,
- *this);
+ *this,
+ feedback_stream);
const uint32_t num_specs = file_specs.GetSize();
@@ -1452,9 +1561,7 @@ Module::LoadScriptingResourceInTarget (Target *target, Error& error, Stream* fee
FileSpec scripting_fspec (file_specs.GetFileSpecAtIndex(i));
if (scripting_fspec && scripting_fspec.Exists())
{
- if (shoud_load == eLoadScriptFromSymFileFalse)
- return false;
- if (shoud_load == eLoadScriptFromSymFileWarn)
+ if (should_load == eLoadScriptFromSymFileWarn)
{
if (feedback_stream)
feedback_stream->Printf("warning: '%s' contains a debug script. To run this script in "
@@ -1584,7 +1691,7 @@ Module::GetVersion (uint32_t *versions, uint32_t num_versions)
if (versions && num_versions)
{
for (uint32_t i=0; i<num_versions; ++i)
- versions[i] = UINT32_MAX;
+ versions[i] = LLDB_INVALID_MODULE_VERSION;
}
return 0;
}
@@ -1644,7 +1751,7 @@ Module::PrepareForFunctionNameLookup (const ConstString &name,
if (!cpp_method.GetQualifiers().empty())
{
- // There is a "const" or other qualifer following the end of the fucntion parens,
+ // There is a "const" or other qualifier following the end of the function parens,
// this can't be a eFunctionNameTypeBase
lookup_name_type_mask &= ~(eFunctionNameTypeBase);
if (lookup_name_type_mask == eFunctionNameTypeNone)
@@ -1693,3 +1800,27 @@ Module::PrepareForFunctionNameLookup (const ConstString &name,
match_name_after_lookup = false;
}
}
+
+ModuleSP
+Module::CreateJITModule (const lldb::ObjectFileJITDelegateSP &delegate_sp)
+{
+ if (delegate_sp)
+ {
+ // Must create a module and place it into a shared pointer before
+ // we can create an object file since it has a std::weak_ptr back
+ // to the module, so we need to control the creation carefully in
+ // this static function
+ ModuleSP module_sp(new Module());
+ module_sp->m_objfile_sp.reset (new ObjectFileJIT (module_sp, delegate_sp));
+ if (module_sp->m_objfile_sp)
+ {
+ // Once we get the object file, update our module with the object file's
+ // architecture since it might differ in vendor/os if some parts were
+ // unknown.
+ module_sp->m_objfile_sp->GetArchitecture (module_sp->m_arch);
+ }
+ return module_sp;
+ }
+ return ModuleSP();
+}
+
diff --git a/source/Core/ModuleList.cpp b/source/Core/ModuleList.cpp
index 215611e42429..156f3cf9d0aa 100644
--- a/source/Core/ModuleList.cpp
+++ b/source/Core/ModuleList.cpp
@@ -10,7 +10,11 @@
#include "lldb/Core/ModuleList.h"
// C Includes
+#include <stdint.h>
+
// C++ Includes
+#include <mutex> // std::once
+
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Log.h"
@@ -40,7 +44,8 @@ ModuleList::ModuleList() :
//----------------------------------------------------------------------
ModuleList::ModuleList(const ModuleList& rhs) :
m_modules(),
- m_modules_mutex (Mutex::eMutexTypeRecursive)
+ m_modules_mutex (Mutex::eMutexTypeRecursive),
+ m_notifier(NULL)
{
Mutex::Locker lhs_locker(m_modules_mutex);
Mutex::Locker rhs_locker(rhs.m_modules_mutex);
@@ -62,9 +67,28 @@ ModuleList::operator= (const ModuleList& rhs)
{
if (this != &rhs)
{
- Mutex::Locker lhs_locker(m_modules_mutex);
- Mutex::Locker rhs_locker(rhs.m_modules_mutex);
- m_modules = rhs.m_modules;
+ // That's probably me nit-picking, but in theoretical situation:
+ //
+ // * that two threads A B and
+ // * two ModuleList's x y do opposite assignemnts ie.:
+ //
+ // in thread A: | in thread B:
+ // x = y; | y = x;
+ //
+ // This establishes correct(same) lock taking order and thus
+ // avoids priority inversion.
+ if (uintptr_t(this) > uintptr_t(&rhs))
+ {
+ Mutex::Locker lhs_locker(m_modules_mutex);
+ Mutex::Locker rhs_locker(rhs.m_modules_mutex);
+ m_modules = rhs.m_modules;
+ }
+ else
+ {
+ Mutex::Locker rhs_locker(rhs.m_modules_mutex);
+ Mutex::Locker lhs_locker(m_modules_mutex);
+ m_modules = rhs.m_modules;
+ }
}
return *this;
}
@@ -832,13 +856,15 @@ ModuleList::GetIndexForModule (const Module *module) const
static ModuleList &
GetSharedModuleList ()
{
- // NOTE: Intentionally leak the module list so a program doesn't have to
- // cleanup all modules and object files as it exits. This just wastes time
- // doing a bunch of cleanup that isn't required.
static ModuleList *g_shared_module_list = NULL;
- if (g_shared_module_list == NULL)
- g_shared_module_list = new ModuleList(); // <--- Intentional leak!!!
-
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, [](){
+ // NOTE: Intentionally leak the module list so a program doesn't have to
+ // cleanup all modules and object files as it exits. This just wastes time
+ // doing a bunch of cleanup that isn't required.
+ if (g_shared_module_list == NULL)
+ g_shared_module_list = new ModuleList(); // <--- Intentional leak!!!
+ });
return *g_shared_module_list;
}
@@ -905,7 +931,7 @@ ModuleList::GetSharedModule
for (size_t module_idx = 0; module_idx < num_matching_modules; ++module_idx)
{
module_sp = matching_module_list.GetModuleAtIndex(module_idx);
-
+
// Make sure the file for the module hasn't been modified
if (module_sp->FileHasChanged())
{
@@ -914,7 +940,8 @@ ModuleList::GetSharedModule
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_MODULES));
if (log)
- log->Printf("module changed: %p, removing from global module list", module_sp.get());
+ log->Printf("module changed: %p, removing from global module list",
+ static_cast<void*>(module_sp.get()));
shared_module_list.Remove (module_sp);
module_sp.reset();
@@ -949,7 +976,7 @@ ModuleList::GetSharedModule
{
if (did_create_ptr)
*did_create_ptr = true;
-
+
shared_module_list.ReplaceEquivalent(module_sp);
return error;
}
@@ -976,6 +1003,7 @@ ModuleList::GetSharedModule
file_spec.GetPath(path, sizeof(path));
if (path[0] == '\0')
module_file_spec.GetPath(path, sizeof(path));
+ // How can this check ever be true? This branch it is false, and we haven't modified file_spec.
if (file_spec.Exists())
{
std::string uuid_str;
@@ -1105,9 +1133,10 @@ ModuleList::LoadScriptingResourcesInTarget (Target *target,
module->GetFileSpec().GetFileNameStrippingExtension().GetCString(),
error.AsCString());
errors.push_back(error);
+
+ if (!continue_on_error)
+ return false;
}
- if (!continue_on_error)
- return false;
}
}
}
diff --git a/source/Core/Opcode.cpp b/source/Core/Opcode.cpp
index 2bf7f5eae9b0..73f5f85923c6 100644
--- a/source/Core/Opcode.cpp
+++ b/source/Core/Opcode.cpp
@@ -63,7 +63,7 @@ Opcode::Dump (Stream *s, uint32_t min_byte_width)
// Add spaces to make sure bytes dispay comes out even in case opcodes
// aren't all the same size
- if (bytes_written < min_byte_width)
+ if (static_cast<uint32_t>(bytes_written) < min_byte_width)
bytes_written = s->Printf ("%*s", min_byte_width - bytes_written, "");
return bytes_written;
}
diff --git a/source/Core/PluginManager.cpp b/source/Core/PluginManager.cpp
index 813cec227525..cda55802fab8 100644
--- a/source/Core/PluginManager.cpp
+++ b/source/Core/PluginManager.cpp
@@ -20,10 +20,12 @@
#include "lldb/Core/Error.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Interpreter/OptionValueProperties.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DynamicLibrary.h"
using namespace lldb;
using namespace lldb_private;
@@ -41,7 +43,12 @@ typedef void (*PluginTermCallback) (void);
struct PluginInfo
{
- void *plugin_handle;
+ PluginInfo()
+ : plugin_init_callback(nullptr), plugin_term_callback(nullptr)
+ {
+ }
+
+ llvm::sys::DynamicLibrary library;
PluginInitCallback plugin_init_callback;
PluginTermCallback plugin_term_callback;
};
@@ -79,6 +86,12 @@ SetPluginInfo (const FileSpec &plugin_file_spec, const PluginInfo &plugin_info)
plugin_map[plugin_file_spec] = plugin_info;
}
+template <typename FPtrTy>
+static FPtrTy
+CastToFPtr (void *VPtr)
+{
+ return reinterpret_cast<FPtrTy>(reinterpret_cast<intptr_t>(VPtr));
+}
static FileSpec::EnumerateDirectoryResult
LoadPluginCallback
@@ -106,16 +119,15 @@ LoadPluginCallback
return FileSpec::eEnumerateDirectoryResultNext;
else
{
- PluginInfo plugin_info = { NULL, NULL, NULL };
- uint32_t flags = Host::eDynamicLibraryOpenOptionLazy |
- Host::eDynamicLibraryOpenOptionLocal |
- Host::eDynamicLibraryOpenOptionLimitGetSymbol;
+ PluginInfo plugin_info;
- plugin_info.plugin_handle = Host::DynamicLibraryOpen (plugin_file_spec, flags, error);
- if (plugin_info.plugin_handle)
+ std::string pluginLoadError;
+ plugin_info.library = llvm::sys::DynamicLibrary::getPermanentLibrary (plugin_file_spec.GetPath().c_str(), &pluginLoadError);
+ if (plugin_info.library.isValid())
{
bool success = false;
- plugin_info.plugin_init_callback = (PluginInitCallback)Host::DynamicLibraryGetSymbol (plugin_info.plugin_handle, "LLDBPluginInitialize", error);
+ plugin_info.plugin_init_callback =
+ CastToFPtr<PluginInitCallback>(plugin_info.library.getAddressOfSymbol("LLDBPluginInitialize"));
if (plugin_info.plugin_init_callback)
{
// Call the plug-in "bool LLDBPluginInitialize(void)" function
@@ -125,16 +137,15 @@ LoadPluginCallback
if (success)
{
// It is ok for the "LLDBPluginTerminate" symbol to be NULL
- plugin_info.plugin_term_callback = (PluginTermCallback)Host::DynamicLibraryGetSymbol (plugin_info.plugin_handle, "LLDBPluginTerminate", error);
+ plugin_info.plugin_term_callback =
+ CastToFPtr<PluginTermCallback>(plugin_info.library.getAddressOfSymbol("LLDBPluginTerminate"));
}
else
{
- // The initialize function returned FALSE which means the
- // plug-in might not be compatible, or might be too new or
- // too old, or might not want to run on this machine.
- Host::DynamicLibraryClose (plugin_info.plugin_handle);
- plugin_info.plugin_handle = NULL;
- plugin_info.plugin_init_callback = NULL;
+ // The initialize function returned FALSE which means the plug-in might not be
+ // compatible, or might be too new or too old, or might not want to run on this
+ // machine. Set it to a default-constructed instance to invalidate it.
+ plugin_info = PluginInfo();
}
// Regardless of success or failure, cache the plug-in load
@@ -153,7 +164,7 @@ LoadPluginCallback
{
// Try and recurse into anything that a directory or symbolic link.
// We must also do this for unknown as sometimes the directory enumeration
- // might be enurating a file system that doesn't have correct file type
+ // might be enumerating a file system that doesn't have correct file type
// information.
return FileSpec::eEnumerateDirectoryResultEnter;
}
@@ -171,7 +182,7 @@ PluginManager::Initialize ()
const bool find_files = true;
const bool find_other = true;
char dir_path[PATH_MAX];
- if (Host::GetLLDBPath (ePathTypeLLDBSystemPlugins, dir_spec))
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBSystemPlugins, dir_spec))
{
if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path)))
{
@@ -184,7 +195,7 @@ PluginManager::Initialize ()
}
}
- if (Host::GetLLDBPath (ePathTypeLLDBUserPlugins, dir_spec))
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBUserPlugins, dir_spec))
{
if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path)))
{
@@ -210,11 +221,10 @@ PluginManager::Terminate ()
{
// Call the plug-in "void LLDBPluginTerminate (void)" function if there
// is one (if the symbol was not NULL).
- if (pos->second.plugin_handle)
+ if (pos->second.library.isValid())
{
if (pos->second.plugin_term_callback)
pos->second.plugin_term_callback();
- Host::DynamicLibraryClose (pos->second.plugin_handle);
}
}
plugin_map.clear();
@@ -544,6 +554,116 @@ PluginManager::GetDynamicLoaderCreateCallbackForPluginName (const ConstString &n
return NULL;
}
+#pragma mark JITLoader
+
+
+struct JITLoaderInstance
+{
+ JITLoaderInstance() :
+ name(),
+ description(),
+ create_callback(NULL),
+ debugger_init_callback (NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ JITLoaderCreateInstance create_callback;
+ DebuggerInitializeCallback debugger_init_callback;
+};
+
+typedef std::vector<JITLoaderInstance> JITLoaderInstances;
+
+
+static Mutex &
+GetJITLoaderMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static JITLoaderInstances &
+GetJITLoaderInstances ()
+{
+ static JITLoaderInstances g_instances;
+ return g_instances;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ JITLoaderCreateInstance create_callback,
+ DebuggerInitializeCallback debugger_init_callback
+)
+{
+ if (create_callback)
+ {
+ JITLoaderInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ instance.debugger_init_callback = debugger_init_callback;
+ Mutex::Locker locker (GetJITLoaderMutex ());
+ GetJITLoaderInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (JITLoaderCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetJITLoaderMutex ());
+ JITLoaderInstances &instances = GetJITLoaderInstances ();
+
+ JITLoaderInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+JITLoaderCreateInstance
+PluginManager::GetJITLoaderCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetJITLoaderMutex ());
+ JITLoaderInstances &instances = GetJITLoaderInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+JITLoaderCreateInstance
+PluginManager::GetJITLoaderCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetJITLoaderMutex ());
+ JITLoaderInstances &instances = GetJITLoaderInstances ();
+
+ JITLoaderInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
#pragma mark EmulateInstruction
@@ -968,7 +1088,8 @@ struct ObjectFileInstance
description(),
create_callback(NULL),
create_memory_callback (NULL),
- get_module_specifications (NULL)
+ get_module_specifications (NULL),
+ save_core (NULL)
{
}
@@ -977,6 +1098,7 @@ struct ObjectFileInstance
ObjectFileCreateInstance create_callback;
ObjectFileCreateMemoryInstance create_memory_callback;
ObjectFileGetModuleSpecifications get_module_specifications;
+ ObjectFileSaveCore save_core;
};
typedef std::vector<ObjectFileInstance> ObjectFileInstances;
@@ -1001,7 +1123,8 @@ PluginManager::RegisterPlugin (const ConstString &name,
const char *description,
ObjectFileCreateInstance create_callback,
ObjectFileCreateMemoryInstance create_memory_callback,
- ObjectFileGetModuleSpecifications get_module_specifications)
+ ObjectFileGetModuleSpecifications get_module_specifications,
+ ObjectFileSaveCore save_core)
{
if (create_callback)
{
@@ -1012,6 +1135,7 @@ PluginManager::RegisterPlugin (const ConstString &name,
instance.description = description;
instance.create_callback = create_callback;
instance.create_memory_callback = create_memory_callback;
+ instance.save_core = save_core;
instance.get_module_specifications = get_module_specifications;
Mutex::Locker locker (GetObjectFileMutex ());
GetObjectFileInstances ().push_back (instance);
@@ -1108,7 +1232,22 @@ PluginManager::GetObjectFileCreateMemoryCallbackForPluginName (const ConstString
return NULL;
}
-
+Error
+PluginManager::SaveCore (const lldb::ProcessSP &process_sp, const FileSpec &outfile)
+{
+ Error error;
+ Mutex::Locker locker (GetObjectFileMutex ());
+ ObjectFileInstances &instances = GetObjectFileInstances ();
+
+ ObjectFileInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->save_core && pos->save_core (process_sp, outfile, error))
+ return error;
+ }
+ error.SetErrorString("no ObjectFile plugins were able to save a core for this process");
+ return error;
+}
#pragma mark ObjectContainer
@@ -1945,6 +2084,19 @@ PluginManager::DebuggerInitialize (Debugger &debugger)
}
}
+ // Initialize the JITLoader plugins
+ {
+ Mutex::Locker locker (GetJITLoaderMutex ());
+ JITLoaderInstances &instances = GetJITLoaderInstances ();
+
+ JITLoaderInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->debugger_init_callback)
+ pos->debugger_init_callback (debugger);
+ }
+ }
+
// Initialize the Platform plugins
{
Mutex::Locker locker (GetPlatformInstancesMutex ());
diff --git a/source/Core/RegularExpression.cpp b/source/Core/RegularExpression.cpp
index 4ccd7748b13e..88415f616828 100644
--- a/source/Core/RegularExpression.cpp
+++ b/source/Core/RegularExpression.cpp
@@ -71,7 +71,7 @@ RegularExpression::operator= (const RegularExpression &rhs)
//----------------------------------------------------------------------
// Destructor
//
-// Any previosuly compiled regular expression contained in this
+// Any previously compiled regular expression contained in this
// object will be freed.
//----------------------------------------------------------------------
RegularExpression::~RegularExpression()
@@ -81,14 +81,14 @@ RegularExpression::~RegularExpression()
//----------------------------------------------------------------------
// Compile a regular expression using the supplied regular
-// expression text and flags. The compied regular expression lives
+// expression text and flags. The compiled regular expression lives
// in this object so that it can be readily used for regular
// expression matches. Execute() can be called after the regular
-// expression is compiled. Any previosuly compiled regular
+// expression is compiled. Any previously compiled regular
// expression contained in this object will be freed.
//
// RETURNS
-// True of the refular expression compiles successfully, false
+// True if the regular expression compiles successfully, false
// otherwise.
//----------------------------------------------------------------------
bool
diff --git a/source/Core/Scalar.cpp b/source/Core/Scalar.cpp
index 26f743796254..1bfe6f2f1baf 100644
--- a/source/Core/Scalar.cpp
+++ b/source/Core/Scalar.cpp
@@ -62,7 +62,7 @@ PromoteToMaxType
promoted_lhs_ptr = &temp_value; // Update the pointer for the promoted left hand side
}
- // Make sure our type promotion worked as exptected
+ // Make sure our type promotion worked as expected
if (promoted_lhs_ptr->GetType() == promoted_rhs_ptr->GetType())
return promoted_lhs_ptr->GetType(); // Return the resulting max type
@@ -1794,7 +1794,7 @@ Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t by
if (!success)
error.SetErrorStringWithFormat ("'%s' is not a valid unsigned integer string value", value_str);
else if (!UIntValueIsValidForSize (uval64, byte_size))
- error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %zu byte unsigned integer value", uval64, byte_size);
+ error.SetErrorStringWithFormat("value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value", uval64, (uint64_t)byte_size);
else
{
m_type = Scalar::GetValueTypeForUnsignedIntegerWithByteSize (byte_size);
@@ -1804,14 +1804,14 @@ Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t by
case e_ulong: m_data.ulong = (ulong_t)uval64; break;
case e_ulonglong: m_data.ulonglong = (ulonglong_t)uval64; break;
default:
- error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %zu", byte_size);
+ error.SetErrorStringWithFormat("unsupported unsigned integer byte size: %" PRIu64 "", (uint64_t)byte_size);
break;
}
}
}
else
{
- error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %zu", byte_size);
+ error.SetErrorStringWithFormat("unsupported unsigned integer byte size: %" PRIu64 "", (uint64_t)byte_size);
return error;
}
break;
@@ -1823,7 +1823,7 @@ Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t by
if (!success)
error.SetErrorStringWithFormat ("'%s' is not a valid signed integer string value", value_str);
else if (!SIntValueIsValidForSize (sval64, byte_size))
- error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %zu byte signed integer value", sval64, byte_size);
+ error.SetErrorStringWithFormat("value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte signed integer value", sval64, (uint64_t)byte_size);
else
{
m_type = Scalar::GetValueTypeForSignedIntegerWithByteSize (byte_size);
@@ -1833,14 +1833,14 @@ Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t by
case e_slong: m_data.slong = (slong_t)sval64; break;
case e_slonglong: m_data.slonglong = (slonglong_t)sval64; break;
default:
- error.SetErrorStringWithFormat ("unsupported signed integer byte size: %zu", byte_size);
+ error.SetErrorStringWithFormat("unsupported signed integer byte size: %" PRIu64 "", (uint64_t)byte_size);
break;
}
}
}
else
{
- error.SetErrorStringWithFormat ("unsupported signed integer byte size: %zu", byte_size);
+ error.SetErrorStringWithFormat("unsupported signed integer byte size: %" PRIu64 "", (uint64_t)byte_size);
return error;
}
break;
@@ -1869,7 +1869,7 @@ Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t by
}
else
{
- error.SetErrorStringWithFormat ("unsupported float byte size: %zu", byte_size);
+ error.SetErrorStringWithFormat("unsupported float byte size: %" PRIu64 "", (uint64_t)byte_size);
return error;
}
break;
@@ -1908,7 +1908,7 @@ Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t b
case 4: operator=((uint32_t)data.GetU32(&offset)); break;
case 8: operator=((uint64_t)data.GetU64(&offset)); break;
default:
- error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %zu", byte_size);
+ error.SetErrorStringWithFormat("unsupported unsigned integer byte size: %" PRIu64 "", (uint64_t)byte_size);
break;
}
}
@@ -1924,7 +1924,7 @@ Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t b
case 4: operator=((int32_t)data.GetU32(&offset)); break;
case 8: operator=((int64_t)data.GetU64(&offset)); break;
default:
- error.SetErrorStringWithFormat ("unsupported signed integer byte size: %zu", byte_size);
+ error.SetErrorStringWithFormat("unsupported signed integer byte size: %" PRIu64 "", (uint64_t)byte_size);
break;
}
}
@@ -1940,7 +1940,7 @@ Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t b
else if (byte_size == sizeof (long double))
operator=((long double)data.GetLongDouble(&offset));
else
- error.SetErrorStringWithFormat ("unsupported float byte size: %zu", byte_size);
+ error.SetErrorStringWithFormat("unsupported float byte size: %" PRIu64 "", (uint64_t)byte_size);
}
break;
}
diff --git a/source/Core/SearchFilter.cpp b/source/Core/SearchFilter.cpp
index 64b5a838d3de..dee2f2e4bd5e 100644
--- a/source/Core/SearchFilter.cpp
+++ b/source/Core/SearchFilter.cpp
@@ -592,7 +592,7 @@ SearchFilterByModuleList::GetDescription (Stream *s)
}
else
{
- s->Printf (", modules(%zu) = ", num_modules);
+ s->Printf(", modules(%" PRIu64 ") = ", (uint64_t)num_modules);
for (size_t i = 0; i < num_modules; i++)
{
if (s->GetVerbose())
diff --git a/source/Core/Section.cpp b/source/Core/Section.cpp
index 28d7d93b9bb9..3267c1866221 100644
--- a/source/Core/Section.cpp
+++ b/source/Core/Section.cpp
@@ -13,6 +13,8 @@
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
+#include <limits>
+
using namespace lldb;
using namespace lldb_private;
@@ -25,6 +27,7 @@ Section::Section (const ModuleSP &module_sp,
addr_t byte_size,
lldb::offset_t file_offset,
lldb::offset_t file_size,
+ uint32_t log2align,
uint32_t flags) :
ModuleChild (module_sp),
UserID (sect_id),
@@ -37,6 +40,7 @@ Section::Section (const ModuleSP &module_sp,
m_byte_size (byte_size),
m_file_offset (file_offset),
m_file_size (file_size),
+ m_log2align (log2align),
m_children (),
m_fake (false),
m_encrypted (false),
@@ -56,6 +60,7 @@ Section::Section (const lldb::SectionSP &parent_section_sp,
addr_t byte_size,
lldb::offset_t file_offset,
lldb::offset_t file_size,
+ uint32_t log2align,
uint32_t flags) :
ModuleChild (module_sp),
UserID (sect_id),
@@ -68,6 +73,7 @@ Section::Section (const lldb::SectionSP &parent_section_sp,
m_byte_size (byte_size),
m_file_offset (file_offset),
m_file_size (file_size),
+ m_log2align (log2align),
m_children (),
m_fake (false),
m_encrypted (false),
@@ -140,7 +146,7 @@ Section::GetLoadBaseAddress (Target *target) const
if (load_base_addr != LLDB_INVALID_ADDRESS)
load_base_addr += GetOffset();
}
- else
+ if (load_base_addr == LLDB_INVALID_ADDRESS)
{
load_base_addr = target->GetSectionLoadList().GetSectionLoadAddress (const_cast<Section *>(this)->shared_from_this());
}
@@ -331,10 +337,14 @@ SectionList::operator = (const SectionList& rhs)
size_t
SectionList::AddSection (const lldb::SectionSP& section_sp)
{
- assert (section_sp.get());
- size_t section_index = m_sections.size();
- m_sections.push_back(section_sp);
- return section_index;
+ if (section_sp)
+ {
+ size_t section_index = m_sections.size();
+ m_sections.push_back(section_sp);
+ return section_index;
+ }
+
+ return std::numeric_limits<size_t>::max ();
}
// Warning, this can be slow as it's removing items from a std::vector.
@@ -433,14 +443,16 @@ SectionList::FindSectionByName (const ConstString &section_dstr) const
for (sect_iter = m_sections.begin(); sect_iter != end && sect_sp.get() == NULL; ++sect_iter)
{
Section *child_section = sect_iter->get();
- assert (child_section);
- if (child_section->GetName() == section_dstr)
- {
- sect_sp = *sect_iter;
- }
- else
+ if (child_section)
{
- sect_sp = child_section->GetChildren().FindSectionByName(section_dstr);
+ if (child_section->GetName() == section_dstr)
+ {
+ sect_sp = *sect_iter;
+ }
+ else
+ {
+ sect_sp = child_section->GetChildren().FindSectionByName(section_dstr);
+ }
}
}
}
diff --git a/source/Core/SourceManager.cpp b/source/Core/SourceManager.cpp
index 0a6a80401d8d..44ab50197c19 100644
--- a/source/Core/SourceManager.cpp
+++ b/source/Core/SourceManager.cpp
@@ -373,7 +373,7 @@ SourceManager::File::File(const FileSpec &file_spec, Target *target) :
{
if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
got_multiple = true;
- break;
+ break;
}
else
test_cu_spec = sc.comp_unit;
diff --git a/source/Core/Stream.cpp b/source/Core/Stream.cpp
index 49c15d63c361..29bebb3ae3db 100644
--- a/source/Core/Stream.cpp
+++ b/source/Core/Stream.cpp
@@ -252,7 +252,7 @@ Stream::EOL()
//------------------------------------------------------------------
// Indent the current line using the current indentation level and
-// print an optional string following the idenatation spaces.
+// print an optional string following the indentation spaces.
//------------------------------------------------------------------
size_t
Stream::Indent(const char *s)
@@ -479,7 +479,7 @@ Stream::PrintfAsRawHex8 (const char *format, ...)
va_list args;
va_list args_copy;
va_start (args, format);
- va_copy (args, args_copy); // Copy this so we
+ va_copy (args_copy,args); // Copy this so we
char str[1024];
size_t bytes_written = 0;
diff --git a/source/Core/StructuredData.cpp b/source/Core/StructuredData.cpp
new file mode 100644
index 000000000000..3c43e41f3c94
--- /dev/null
+++ b/source/Core/StructuredData.cpp
@@ -0,0 +1,429 @@
+//===---------------------StructuredData.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/Core/StructuredData.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+using namespace lldb_private;
+
+
+static StructuredData::ObjectSP read_json_object (const char **ch);
+static StructuredData::ObjectSP read_json_array (const char **ch);
+
+static StructuredData::ObjectSP
+read_json_number (const char **ch)
+{
+ StructuredData::ObjectSP object_sp;
+ while (isspace (**ch))
+ (*ch)++;
+ const char *start_of_number = *ch;
+ bool is_integer = true;
+ bool is_float = false;
+ while (isdigit(**ch) || **ch == '-' || **ch == '.' || **ch == '+' || **ch == 'e' || **ch == 'E')
+ {
+ if (isdigit(**ch) == false && **ch != '-')
+ {
+ is_integer = false;
+ is_float = true;
+ }
+ (*ch)++;
+ }
+ while (isspace (**ch))
+ (*ch)++;
+ if (**ch == ',' || **ch == ']' || **ch == '}')
+ {
+ if (is_integer)
+ {
+ errno = 0;
+ uint64_t val = strtoul (start_of_number, NULL, 10);
+ if (errno == 0)
+ {
+ object_sp.reset(new StructuredData::Integer());
+ object_sp->GetAsInteger()->SetValue (val);
+ }
+ }
+ if (is_float)
+ {
+ char *end_of_number = NULL;
+ errno = 0;
+ double val = strtod (start_of_number, &end_of_number);
+ if (errno == 0 && end_of_number != start_of_number && end_of_number != NULL)
+ {
+ object_sp.reset(new StructuredData::Float());
+ object_sp->GetAsFloat()->SetValue (val);
+ }
+ }
+ }
+ return object_sp;
+}
+
+static std::string
+read_json_string (const char **ch)
+{
+ std::string string;
+ if (**ch == '"')
+ {
+ (*ch)++;
+ while (**ch != '\0')
+ {
+ if (**ch == '"')
+ {
+ (*ch)++;
+ while (isspace (**ch))
+ (*ch)++;
+ break;
+ }
+ else if (**ch == '\\')
+ {
+ switch (**ch)
+ {
+ case '"':
+ string.push_back('"');
+ *ch += 2;
+ break;
+ case '\\':
+ string.push_back('\\');
+ *ch += 2;
+ break;
+ case '/':
+ string.push_back('/');
+ *ch += 2;
+ break;
+ case 'b':
+ string.push_back('\b');
+ *ch += 2;
+ break;
+ case 'f':
+ string.push_back('\f');
+ *ch += 2;
+ break;
+ case 'n':
+ string.push_back('\n');
+ *ch += 2;
+ break;
+ case 'r':
+ string.push_back('\r');
+ *ch += 2;
+ break;
+ case 't':
+ string.push_back('\t');
+ *ch += 2;
+ break;
+ case 'u':
+ // FIXME handle four-hex-digits
+ *ch += 10;
+ break;
+ default:
+ *ch += 1;
+ }
+ }
+ else
+ {
+ string.push_back (**ch);
+ }
+ (*ch)++;
+ }
+ }
+ return string;
+}
+
+static StructuredData::ObjectSP
+read_json_value (const char **ch)
+{
+ StructuredData::ObjectSP object_sp;
+ while (isspace (**ch))
+ (*ch)++;
+
+ if (**ch == '{')
+ {
+ object_sp = read_json_object (ch);
+ }
+ else if (**ch == '[')
+ {
+ object_sp = read_json_array (ch);
+ }
+ else if (**ch == '"')
+ {
+ std::string string = read_json_string (ch);
+ object_sp.reset(new StructuredData::String());
+ object_sp->GetAsString()->SetValue(string);
+ }
+ else
+ {
+ if (strncmp (*ch, "true", 4) == 0)
+ {
+ object_sp.reset(new StructuredData::Boolean());
+ object_sp->GetAsBoolean()->SetValue(true);
+ *ch += 4;
+ }
+ else if (strncmp (*ch, "false", 5) == 0)
+ {
+ object_sp.reset(new StructuredData::Boolean());
+ object_sp->GetAsBoolean()->SetValue(false);
+ *ch += 5;
+ }
+ else if (strncmp (*ch, "null", 4) == 0)
+ {
+ object_sp.reset(new StructuredData::Null());
+ *ch += 4;
+ }
+ else
+ {
+ object_sp = read_json_number (ch);
+ }
+ }
+ return object_sp;
+}
+
+static StructuredData::ObjectSP
+read_json_array (const char **ch)
+{
+ StructuredData::ObjectSP object_sp;
+ if (**ch == '[')
+ {
+ (*ch)++;
+ while (isspace (**ch))
+ (*ch)++;
+
+ bool first_value = true;
+ while (**ch != '\0' && (first_value || **ch == ','))
+ {
+ if (**ch == ',')
+ (*ch)++;
+ first_value = false;
+ while (isspace (**ch))
+ (*ch)++;
+ lldb_private::StructuredData::ObjectSP value_sp = read_json_value (ch);
+ if (value_sp)
+ {
+ if (object_sp.get() == NULL)
+ {
+ object_sp.reset(new StructuredData::Array());
+ }
+ object_sp->GetAsArray()->Push (value_sp);
+ }
+ while (isspace (**ch))
+ (*ch)++;
+ }
+ if (**ch == ']')
+ {
+ // FIXME should throw an error if we don't see a } to close out the JSON object
+ (*ch)++;
+ while (isspace (**ch))
+ (*ch)++;
+ }
+ }
+ return object_sp;
+}
+
+static StructuredData::ObjectSP
+read_json_object (const char **ch)
+{
+ StructuredData::ObjectSP object_sp;
+ if (**ch == '{')
+ {
+ (*ch)++;
+ while (isspace (**ch))
+ (*ch)++;
+ bool first_pair = true;
+ while (**ch != '\0' && (first_pair || **ch == ','))
+ {
+ first_pair = false;
+ if (**ch == ',')
+ (*ch)++;
+ while (isspace (**ch))
+ (*ch)++;
+ if (**ch != '"')
+ break;
+ std::string key_string = read_json_string (ch);
+ while (isspace (**ch))
+ (*ch)++;
+ if (key_string.size() > 0 && **ch == ':')
+ {
+ (*ch)++;
+ while (isspace (**ch))
+ (*ch)++;
+ lldb_private::StructuredData::ObjectSP value_sp = read_json_value (ch);
+ if (value_sp.get())
+ {
+ if (object_sp.get() == NULL)
+ {
+ object_sp.reset(new StructuredData::Dictionary());
+ }
+ object_sp->GetAsDictionary()->AddItem (key_string.c_str(), value_sp);
+ }
+ }
+ while (isspace (**ch))
+ (*ch)++;
+ }
+ if (**ch == '}')
+ {
+ // FIXME should throw an error if we don't see a } to close out the JSON object
+ (*ch)++;
+ while (isspace (**ch))
+ (*ch)++;
+ }
+ }
+ return object_sp;
+}
+
+
+StructuredData::ObjectSP
+StructuredData::ParseJSON (std::string json_text)
+{
+ StructuredData::ObjectSP object_sp;
+ const size_t json_text_size = json_text.size();
+ if (json_text_size > 0)
+ {
+ const char *start_of_json_text = json_text.c_str();
+ const char *c = json_text.c_str();
+ while (*c != '\0' &&
+ static_cast<size_t>(c - start_of_json_text) <= json_text_size)
+ {
+ while (isspace (*c) &&
+ static_cast<size_t>(c - start_of_json_text) < json_text_size)
+ c++;
+ if (*c == '{')
+ {
+ object_sp = read_json_object (&c);
+ }
+ else
+ {
+ // We have bad characters here, this is likely an illegal JSON string.
+ return object_sp;
+ }
+ }
+ }
+ return object_sp;
+}
+
+StructuredData::ObjectSP
+StructuredData::Object::GetObjectForDotSeparatedPath (llvm::StringRef path)
+{
+ if (this->GetType() == Type::eTypeDictionary)
+ {
+ std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
+ std::string key = match.first.str();
+ ObjectSP value = this->GetAsDictionary()->GetValueForKey (key.c_str());
+ if (value.get())
+ {
+ // Do we have additional words to descend? If not, return the
+ // value we're at right now.
+ if (match.second.empty())
+ {
+ return value;
+ }
+ else
+ {
+ return value->GetObjectForDotSeparatedPath (match.second);
+ }
+ }
+ return ObjectSP();
+ }
+
+ if (this->GetType() == Type::eTypeArray)
+ {
+ std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
+ if (match.second.size() == 0)
+ {
+ return this->shared_from_this();
+ }
+ errno = 0;
+ uint64_t val = strtoul (match.second.str().c_str(), NULL, 10);
+ if (errno == 0)
+ {
+ return this->GetAsArray()->GetItemAtIndex(val);
+ }
+ return ObjectSP();
+ }
+
+ return this->shared_from_this();
+}
+
+void
+StructuredData::Array::Dump (Stream &s) const
+{
+ s << "[";
+ const size_t arrsize = m_items.size();
+ for (size_t i = 0; i < arrsize; ++i)
+ {
+ m_items[i]->Dump(s);
+ if (i + 1 < arrsize)
+ s << ",";
+ }
+ s << "]";
+}
+
+void
+StructuredData::Integer::Dump (Stream &s) const
+{
+ s.Printf ("%" PRIu64, m_value);
+}
+
+
+void
+StructuredData::Float::Dump (Stream &s) const
+{
+ s.Printf ("%lf", m_value);
+}
+
+void
+StructuredData::Boolean::Dump (Stream &s) const
+{
+ if (m_value == true)
+ s.PutCString ("true");
+ else
+ s.PutCString ("false");
+}
+
+
+void
+StructuredData::String::Dump (Stream &s) const
+{
+ std::string quoted;
+ const size_t strsize = m_value.size();
+ for (size_t i = 0; i < strsize ; ++i)
+ {
+ char ch = m_value[i];
+ if (ch == '"')
+ quoted.push_back ('\\');
+ quoted.push_back (ch);
+ }
+ s.Printf ("\"%s\"", quoted.c_str());
+}
+
+void
+StructuredData::Dictionary::Dump (Stream &s) const
+{
+ bool have_printed_one_elem = false;
+ s << "{";
+ for (collection::const_iterator iter = m_dict.begin(); iter != m_dict.end(); ++iter)
+ {
+ if (have_printed_one_elem == false)
+ {
+ have_printed_one_elem = true;
+ }
+ else
+ {
+ s << ",";
+ }
+ s << "\"" << iter->first.AsCString() << "\":";
+ iter->second->Dump(s);
+ }
+ s << "}";
+}
+
+void
+StructuredData::Null::Dump (Stream &s) const
+{
+ s << "null";
+}
diff --git a/source/Core/Value.cpp b/source/Core/Value.cpp
index 9d42a3774624..db33fce4a03e 100644
--- a/source/Core/Value.cpp
+++ b/source/Core/Value.cpp
@@ -55,7 +55,7 @@ Value::Value(const Scalar& scalar) :
}
-Value::Value(const uint8_t *bytes, int len) :
+Value::Value(const void *bytes, int len) :
m_value (),
m_vector (),
m_clang_type (),
@@ -64,8 +64,7 @@ Value::Value(const uint8_t *bytes, int len) :
m_context_type (eContextTypeInvalid),
m_data_buffer ()
{
- m_data_buffer.CopyData(bytes, len);
- m_value = (uintptr_t)m_data_buffer.GetBytes();
+ SetBytes(bytes, len);
}
Value::Value(const Value &v) :
@@ -77,7 +76,8 @@ Value::Value(const Value &v) :
m_context_type (v.m_context_type),
m_data_buffer ()
{
- if ((uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS) == (uintptr_t)v.m_data_buffer.GetBytes())
+ const uintptr_t rhs_value = (uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ if ((rhs_value != 0) && (rhs_value == (uintptr_t)v.m_data_buffer.GetBytes()))
{
m_data_buffer.CopyData(v.m_data_buffer.GetBytes(),
v.m_data_buffer.GetByteSize());
@@ -97,7 +97,8 @@ Value::operator=(const Value &rhs)
m_context = rhs.m_context;
m_value_type = rhs.m_value_type;
m_context_type = rhs.m_context_type;
- if ((uintptr_t)rhs.m_value.ULongLong(LLDB_INVALID_ADDRESS) == (uintptr_t)rhs.m_data_buffer.GetBytes())
+ const uintptr_t rhs_value = (uintptr_t)rhs.m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ if ((rhs_value != 0) && (rhs_value == (uintptr_t)rhs.m_data_buffer.GetBytes()))
{
m_data_buffer.CopyData(rhs.m_data_buffer.GetBytes(),
rhs.m_data_buffer.GetByteSize());
@@ -109,6 +110,22 @@ Value::operator=(const Value &rhs)
}
void
+Value::SetBytes (const void *bytes, int len)
+{
+ m_value_type = eValueTypeHostAddress;
+ m_data_buffer.CopyData(bytes, len);
+ m_value = (uintptr_t)m_data_buffer.GetBytes();
+}
+
+void
+Value::AppendBytes (const void *bytes, int len)
+{
+ m_value_type = eValueTypeHostAddress;
+ m_data_buffer.AppendData (bytes, len);
+ m_value = (uintptr_t)m_data_buffer.GetBytes();
+}
+
+void
Value::Dump (Stream* strm)
{
m_value.GetValue (strm, true);
@@ -155,12 +172,74 @@ Value::GetType()
return NULL;
}
-void
+size_t
+Value::AppendDataToHostBuffer (const Value &rhs)
+{
+ size_t curr_size = m_data_buffer.GetByteSize();
+ Error error;
+ switch (rhs.GetValueType())
+ {
+ case eValueTypeScalar:
+ {
+ const size_t scalar_size = rhs.m_value.GetByteSize();
+ if (scalar_size > 0)
+ {
+ const size_t new_size = curr_size + scalar_size;
+ if (ResizeData(new_size) == new_size)
+ {
+ rhs.m_value.GetAsMemoryData (m_data_buffer.GetBytes() + curr_size,
+ scalar_size,
+ lldb::endian::InlHostByteOrder(),
+ error);
+ return scalar_size;
+ }
+ }
+ }
+ break;
+ case eValueTypeVector:
+ {
+ const size_t vector_size = rhs.m_vector.length;
+ if (vector_size > 0)
+ {
+ const size_t new_size = curr_size + vector_size;
+ if (ResizeData(new_size) == new_size)
+ {
+ ::memcpy (m_data_buffer.GetBytes() + curr_size,
+ rhs.m_vector.bytes,
+ vector_size);
+ return vector_size;
+ }
+ }
+ }
+ break;
+ case eValueTypeFileAddress:
+ case eValueTypeLoadAddress:
+ case eValueTypeHostAddress:
+ {
+ const uint8_t *src = rhs.GetBuffer().GetBytes();
+ const size_t src_len = rhs.GetBuffer().GetByteSize();
+ if (src && src_len > 0)
+ {
+ const size_t new_size = curr_size + src_len;
+ if (ResizeData(new_size) == new_size)
+ {
+ ::memcpy (m_data_buffer.GetBytes() + curr_size, src, src_len);
+ return src_len;
+ }
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+size_t
Value::ResizeData(size_t len)
{
m_value_type = eValueTypeHostAddress;
m_data_buffer.SetByteSize(len);
m_value = (uintptr_t)m_data_buffer.GetBytes();
+ return m_data_buffer.GetByteSize();
}
bool
@@ -579,7 +658,12 @@ Value::GetValueAsData (ExecutionContext *exe_ctx,
{
if (address_type == eAddressTypeHost)
{
- // The address is an address in this process, so just copy it
+ // The address is an address in this process, so just copy it.
+ if (address == 0)
+ {
+ error.SetErrorStringWithFormat("trying to read from host address of 0.");
+ return error;
+ }
memcpy (dst, (uint8_t*)NULL + address, byte_size);
}
else if ((address_type == eAddressTypeLoad) || (address_type == eAddressTypeFile))
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp
index 10e5ab452f0f..1819e834536a 100644
--- a/source/Core/ValueObject.cpp
+++ b/source/Core/ValueObject.cpp
@@ -237,28 +237,25 @@ ValueObject::UpdateFormatsIfNeeded()
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
if (log)
log->Printf("[%s %p] checking for FormatManager revisions. ValueObject rev: %d - Global rev: %d",
- GetName().GetCString(),
- this,
- m_last_format_mgr_revision,
- DataVisualization::GetCurrentRevision());
-
+ GetName().GetCString(), static_cast<void*>(this),
+ m_last_format_mgr_revision,
+ DataVisualization::GetCurrentRevision());
+
bool any_change = false;
-
+
if ( (m_last_format_mgr_revision != DataVisualization::GetCurrentRevision()))
{
+ m_last_format_mgr_revision = DataVisualization::GetCurrentRevision();
+ any_change = true;
+
SetValueFormat(DataVisualization::GetFormat (*this, eNoDynamicValues));
SetSummaryFormat(DataVisualization::GetSummaryFormat (*this, GetDynamicValueType()));
#ifndef LLDB_DISABLE_PYTHON
SetSyntheticChildren(DataVisualization::GetSyntheticChildren (*this, GetDynamicValueType()));
#endif
-
- m_last_format_mgr_revision = DataVisualization::GetCurrentRevision();
-
- any_change = true;
}
-
+
return any_change;
-
}
void
@@ -796,7 +793,6 @@ ValueObject::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_
ExecutionContext exe_ctx (GetExecutionContextRef());
child_clang_type = GetClangType().GetChildClangTypeAtIndex (&exe_ctx,
- GetName().GetCString(),
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -807,7 +803,8 @@ ValueObject::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- child_is_deref_of_parent);
+ child_is_deref_of_parent,
+ this);
if (child_clang_type)
{
if (synthetic_index)
@@ -978,14 +975,15 @@ ValueObject::GetPointeeData (DataExtractor& data,
ValueObjectSP pointee_sp = Dereference(error);
if (error.Fail() || pointee_sp.get() == NULL)
return 0;
- return pointee_sp->GetData(data);
+ return pointee_sp->GetData(data, error);
}
else
{
ValueObjectSP child_sp = GetChildAtIndex(0, true);
if (child_sp.get() == NULL)
return 0;
- return child_sp->GetData(data);
+ Error error;
+ return child_sp->GetData(data, error);
}
return true;
}
@@ -1059,11 +1057,11 @@ ValueObject::GetPointeeData (DataExtractor& data,
}
uint64_t
-ValueObject::GetData (DataExtractor& data)
+ValueObject::GetData (DataExtractor& data, Error &error)
{
UpdateValueIfNeeded(false);
ExecutionContext exe_ctx (GetExecutionContextRef());
- Error error = m_value.GetValueAsData(&exe_ctx, data, 0, GetModule().get());
+ error = m_value.GetValueAsData(&exe_ctx, data, 0, GetModule().get());
if (error.Fail())
{
if (m_data.GetByteSize())
@@ -1707,7 +1705,7 @@ ValueObject::DumpPrintableRepresentation(Stream& s,
break;
case eValueObjectRepresentationStyleChildrenCount:
- strm.Printf("%zu", GetNumChildren());
+ strm.Printf("%" PRIu64 "", (uint64_t)GetNumChildren());
cstr = strm.GetString().c_str();
break;
@@ -1955,6 +1953,12 @@ ValueObject::GetTypeName()
}
ConstString
+ValueObject::GetDisplayTypeName()
+{
+ return GetTypeName();
+}
+
+ConstString
ValueObject::GetQualifiedTypeName()
{
return GetClangType().GetConstQualifiedTypeName();
@@ -2063,7 +2067,7 @@ ValueObject::GetSyntheticArrayMemberFromPointer (size_t index, bool can_create)
if (IsPointerType ())
{
char index_str[64];
- snprintf(index_str, sizeof(index_str), "[%zu]", index);
+ snprintf(index_str, sizeof(index_str), "[%" PRIu64 "]", (uint64_t)index);
ConstString index_const_str(index_str);
// Check if we have already created a synthetic array member in this
// valid object. If we have we will re-use it.
@@ -2106,7 +2110,7 @@ ValueObject::GetSyntheticArrayMemberFromArray (size_t index, bool can_create)
if (IsArrayType ())
{
char index_str[64];
- snprintf(index_str, sizeof(index_str), "[%zu]", index);
+ snprintf(index_str, sizeof(index_str), "[%" PRIu64 "]", (uint64_t)index);
ConstString index_const_str(index_str);
// Check if we have already created a synthetic array member in this
// valid object. If we have we will re-use it.
@@ -2211,6 +2215,47 @@ ValueObject::GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type
return synthetic_child_sp;
}
+ValueObjectSP
+ValueObject::GetSyntheticBase (uint32_t offset, const ClangASTType& type, bool can_create)
+{
+ ValueObjectSP synthetic_child_sp;
+
+ char name_str[64];
+ snprintf(name_str, sizeof(name_str), "%s", type.GetTypeName().AsCString("<unknown>"));
+ ConstString name_const_str(name_str);
+
+ // Check if we have already created a synthetic array member in this
+ // valid object. If we have we will re-use it.
+ synthetic_child_sp = GetSyntheticChild (name_const_str);
+
+ if (synthetic_child_sp.get())
+ return synthetic_child_sp;
+
+ if (!can_create)
+ return ValueObjectSP();
+
+ const bool is_base_class = true;
+
+ ValueObjectChild *synthetic_child = new ValueObjectChild(*this,
+ type,
+ name_const_str,
+ type.GetByteSize(),
+ offset,
+ 0,
+ 0,
+ is_base_class,
+ false,
+ eAddressTypeInvalid);
+ if (synthetic_child)
+ {
+ AddSyntheticChild(name_const_str, synthetic_child);
+ synthetic_child_sp = synthetic_child->GetSP();
+ synthetic_child_sp->SetName(name_const_str);
+ }
+ return synthetic_child_sp;
+}
+
+
// your expression path needs to have a leading . or ->
// (unless it somehow "looks like" an array, in which case it has
// a leading [ symbol). while the [ is meaningful and should be shown
@@ -2392,6 +2437,26 @@ ValueObject::GetNonBaseClassParent()
return NULL;
}
+
+bool
+ValueObject::IsBaseClass (uint32_t& depth)
+{
+ if (!IsBaseClass())
+ {
+ depth = 0;
+ return false;
+ }
+ if (GetParent())
+ {
+ GetParent()->IsBaseClass(depth);
+ depth = depth + 1;
+ return true;
+ }
+ // TODO: a base of no parent? weird..
+ depth = 1;
+ return true;
+}
+
void
ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat epformat)
{
@@ -3464,6 +3529,38 @@ ValueObject::CreateConstantValue (const ConstString &name)
return valobj_sp;
}
+lldb::addr_t
+ValueObject::GetCPPVTableAddress (AddressType &address_type)
+{
+ ClangASTType pointee_type;
+ ClangASTType this_type(GetClangType());
+ uint32_t type_info = this_type.GetTypeInfo(&pointee_type);
+ if (type_info)
+ {
+ bool ptr_or_ref = false;
+ if (type_info & (ClangASTType::eTypeIsPointer | ClangASTType::eTypeIsReference))
+ {
+ ptr_or_ref = true;
+ type_info = pointee_type.GetTypeInfo();
+ }
+
+ const uint32_t cpp_class = ClangASTType::eTypeIsClass | ClangASTType::eTypeIsCPlusPlus;
+ if ((type_info & cpp_class) == cpp_class)
+ {
+ if (ptr_or_ref)
+ {
+ address_type = GetAddressTypeOfChildren();
+ return GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ }
+ else
+ return GetAddressOf (false, &address_type);
+ }
+ }
+
+ address_type = eAddressTypeInvalid;
+ return LLDB_INVALID_ADDRESS;
+}
+
ValueObjectSP
ValueObject::Dereference (Error &error)
{
@@ -3490,7 +3587,6 @@ ValueObject::Dereference (Error &error)
ExecutionContext exe_ctx (GetExecutionContextRef());
child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
- GetName().GetCString(),
0,
transparent_pointers,
omit_empty_base_classes,
@@ -3501,7 +3597,8 @@ ValueObject::Dereference (Error &error)
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- child_is_deref_of_parent);
+ child_is_deref_of_parent,
+ this);
if (child_clang_type && child_byte_size)
{
ConstString child_name;
@@ -3881,7 +3978,7 @@ ValueObject::CreateValueObjectFromAddress (const char* name,
lldb::ValueObjectSP
ValueObject::CreateValueObjectFromData (const char* name,
- DataExtractor& data,
+ const DataExtractor& data,
const ExecutionContext& exe_ctx,
ClangASTType type)
{
diff --git a/source/Core/ValueObjectChild.cpp b/source/Core/ValueObjectChild.cpp
index ccf87cd15b24..33b91f9e30d1 100644
--- a/source/Core/ValueObjectChild.cpp
+++ b/source/Core/ValueObjectChild.cpp
@@ -66,25 +66,29 @@ ValueObjectChild::CalculateNumChildren()
return GetClangType().GetNumChildren (true);
}
+static void
+AdjustForBitfieldness(ConstString& name,
+ uint8_t bitfield_bit_size)
+{
+ if (name && bitfield_bit_size)
+ {
+ const char *clang_type_name = name.AsCString();
+ if (clang_type_name)
+ {
+ std::vector<char> bitfield_type_name (strlen(clang_type_name) + 32, 0);
+ ::snprintf (&bitfield_type_name.front(), bitfield_type_name.size(), "%s:%u", clang_type_name, bitfield_bit_size);
+ name.SetCString(&bitfield_type_name.front());
+ }
+ }
+}
+
ConstString
ValueObjectChild::GetTypeName()
{
if (m_type_name.IsEmpty())
{
m_type_name = GetClangType().GetConstTypeName ();
- if (m_type_name)
- {
- if (m_bitfield_bit_size > 0)
- {
- const char *clang_type_name = m_type_name.AsCString();
- if (clang_type_name)
- {
- std::vector<char> bitfield_type_name (strlen(clang_type_name) + 32, 0);
- ::snprintf (&bitfield_type_name.front(), bitfield_type_name.size(), "%s:%u", clang_type_name, m_bitfield_bit_size);
- m_type_name.SetCString(&bitfield_type_name.front());
- }
- }
- }
+ AdjustForBitfieldness(m_type_name, m_bitfield_bit_size);
}
return m_type_name;
}
@@ -93,22 +97,18 @@ ConstString
ValueObjectChild::GetQualifiedTypeName()
{
ConstString qualified_name = GetClangType().GetConstTypeName();
- if (qualified_name)
- {
- if (m_bitfield_bit_size > 0)
- {
- const char *clang_type_name = qualified_name.AsCString();
- if (clang_type_name)
- {
- std::vector<char> bitfield_type_name (strlen(clang_type_name) + 32, 0);
- ::snprintf (&bitfield_type_name.front(), bitfield_type_name.size(), "%s:%u", clang_type_name, m_bitfield_bit_size);
- qualified_name.SetCString(&bitfield_type_name.front());
- }
- }
- }
+ AdjustForBitfieldness(qualified_name, m_bitfield_bit_size);
return qualified_name;
}
+ConstString
+ValueObjectChild::GetDisplayTypeName()
+{
+ ConstString display_name = GetClangType().GetDisplayTypeName();
+ AdjustForBitfieldness(display_name, m_bitfield_bit_size);
+ return display_name;
+}
+
bool
ValueObjectChild::UpdateValue ()
{
diff --git a/source/Core/ValueObjectConstResult.cpp b/source/Core/ValueObjectConstResult.cpp
index d6d86381358d..387e171e3526 100644
--- a/source/Core/ValueObjectConstResult.cpp
+++ b/source/Core/ValueObjectConstResult.cpp
@@ -276,6 +276,12 @@ ValueObjectConstResult::GetTypeName()
return m_type_name;
}
+ConstString
+ValueObjectConstResult::GetDisplayTypeName()
+{
+ return GetClangType().GetDisplayTypeName();
+}
+
bool
ValueObjectConstResult::UpdateValue ()
{
diff --git a/source/Core/ValueObjectConstResultImpl.cpp b/source/Core/ValueObjectConstResultImpl.cpp
index e0757f60cdba..d3e275883509 100644
--- a/source/Core/ValueObjectConstResultImpl.cpp
+++ b/source/Core/ValueObjectConstResultImpl.cpp
@@ -31,7 +31,7 @@ using namespace lldb;
using namespace lldb_private;
// this macro enables a simpler implementation for some method calls in this object that relies only upon
-// ValueObject knowning how to set the address type of its children correctly. the alternative implementation
+// ValueObject knowing how to set the address type of its children correctly. the alternative implementation
// relies on being able to create a target copy of the frozen object, which makes it less bug-prone but less
// efficient as well. once we are confident the faster implementation is bug-free, this macro (and the slower
// implementations) can go
@@ -109,7 +109,6 @@ ValueObjectConstResultImpl::CreateChildAtIndex (size_t idx, bool synthetic_array
ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
- m_impl_backend->GetName().GetCString(),
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -120,7 +119,8 @@ ValueObjectConstResultImpl::CreateChildAtIndex (size_t idx, bool synthetic_array
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- child_is_deref_of_parent);
+ child_is_deref_of_parent,
+ m_impl_backend);
if (child_clang_type && child_byte_size)
{
if (synthetic_index)
diff --git a/source/Core/ValueObjectDynamicValue.cpp b/source/Core/ValueObjectDynamicValue.cpp
index 47e781e71156..a6fad7a9b1fd 100644
--- a/source/Core/ValueObjectDynamicValue.cpp
+++ b/source/Core/ValueObjectDynamicValue.cpp
@@ -71,8 +71,6 @@ ValueObjectDynamicValue::GetTypeName()
{
if (m_dynamic_type_info.HasName())
return m_dynamic_type_info.GetName();
- if (m_dynamic_type_info.HasType())
- return GetClangType().GetConstTypeName();
}
return m_parent->GetTypeName();
}
@@ -96,10 +94,22 @@ ValueObjectDynamicValue::GetQualifiedTypeName()
{
if (m_dynamic_type_info.HasName())
return m_dynamic_type_info.GetName();
+ }
+ return m_parent->GetQualifiedTypeName();
+}
+
+ConstString
+ValueObjectDynamicValue::GetDisplayTypeName()
+{
+ const bool success = UpdateValueIfNeeded(false);
+ if (success)
+ {
if (m_dynamic_type_info.HasType())
- return GetClangType().GetConstQualifiedTypeName ();
+ return GetClangType().GetDisplayTypeName();
+ if (m_dynamic_type_info.HasName())
+ return m_dynamic_type_info.GetName();
}
- return m_parent->GetTypeName();
+ return m_parent->GetDisplayTypeName();
}
size_t
@@ -175,7 +185,7 @@ ValueObjectDynamicValue::UpdateValue ()
m_error = m_parent->GetError();
return false;
}
-
+
// Setting our type_sp to NULL will route everything back through our
// parent which is equivalent to not using dynamic values.
if (m_use_dynamic == lldb::eNoDynamicValues)
@@ -183,7 +193,7 @@ ValueObjectDynamicValue::UpdateValue ()
m_dynamic_type_info.Clear();
return true;
}
-
+
ExecutionContext exe_ctx (GetExecutionContextRef());
Target *target = exe_ctx.GetTargetPtr();
if (target)
@@ -191,16 +201,16 @@ ValueObjectDynamicValue::UpdateValue ()
m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());
m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
}
-
+
// First make sure our Type and/or Address haven't changed:
Process *process = exe_ctx.GetProcessPtr();
if (!process)
return false;
-
+
TypeAndOrName class_type_or_name;
Address dynamic_address;
bool found_dynamic_type = false;
-
+
lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage();
if (known_type != lldb::eLanguageTypeUnknown && known_type != lldb::eLanguageTypeC)
{
@@ -213,7 +223,7 @@ ValueObjectDynamicValue::UpdateValue ()
LanguageRuntime *cpp_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeC_plus_plus);
if (cpp_runtime)
found_dynamic_type = cpp_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address);
-
+
if (!found_dynamic_type)
{
LanguageRuntime *objc_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeObjC);
@@ -221,10 +231,10 @@ ValueObjectDynamicValue::UpdateValue ()
found_dynamic_type = objc_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address);
}
}
-
+
// Getting the dynamic value may have run the program a bit, and so marked us as needing updating, but we really
// don't...
-
+
m_update_point.SetUpdated();
if (found_dynamic_type)
@@ -251,7 +261,7 @@ ValueObjectDynamicValue::UpdateValue ()
{
m_type_impl.Clear();
}
-
+
// If we don't have a dynamic type, then make ourselves just a echo of our parent.
// Or we could return false, and make ourselves an echo of our parent?
if (!found_dynamic_type)
@@ -264,13 +274,13 @@ ValueObjectDynamicValue::UpdateValue ()
m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
return m_error.Success();
}
-
+
Value old_value(m_value);
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
-
+
bool has_changed_type = false;
-
+
if (!m_dynamic_type_info)
{
m_dynamic_type_info = class_type_or_name;
@@ -283,37 +293,35 @@ ValueObjectDynamicValue::UpdateValue ()
SetValueDidChange (true);
has_changed_type = true;
}
-
+
if (has_changed_type)
ClearDynamicTypeInformation ();
-
+
if (!m_address.IsValid() || m_address != dynamic_address)
{
if (m_address.IsValid())
SetValueDidChange (true);
-
+
// We've moved, so we should be fine...
m_address = dynamic_address;
lldb::TargetSP target_sp (GetTargetSP());
lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());
m_value.GetScalar() = load_address;
}
-
+
m_dynamic_type_info = FixupTypeAndOrName(m_dynamic_type_info, *m_parent);
-
+
//m_value.SetContext (Value::eContextTypeClangType, corrected_type);
m_value.SetClangType (m_dynamic_type_info.GetClangASTType());
-
+
// Our address is the location of the dynamic type stored in memory. It isn't a load address,
// because we aren't pointing to the LOCATION that stores the pointer to us, we're pointing to us...
m_value.SetValueType(Value::eValueTypeScalar);
if (has_changed_type && log)
- log->Printf("[%s %p] has a new dynamic type %s",
- GetName().GetCString(),
- this,
- GetTypeName().GetCString());
-
+ log->Printf("[%s %p] has a new dynamic type %s", GetName().GetCString(),
+ static_cast<void*>(this), GetTypeName().GetCString());
+
if (m_address.IsValid() && m_dynamic_type_info)
{
// The variable value is in the Scalar value inside the m_value.
@@ -333,7 +341,7 @@ ValueObjectDynamicValue::UpdateValue ()
return true;
}
}
-
+
// We get here if we've failed above...
SetValueIsValid (false);
return false;
diff --git a/source/Core/ValueObjectMemory.cpp b/source/Core/ValueObjectMemory.cpp
index 42fd0e8fffba..d2cbbfdda240 100644
--- a/source/Core/ValueObjectMemory.cpp
+++ b/source/Core/ValueObjectMemory.cpp
@@ -147,6 +147,14 @@ ValueObjectMemory::GetTypeName()
return m_clang_type.GetConstTypeName();
}
+ConstString
+ValueObjectMemory::GetDisplayTypeName()
+{
+ if (m_type_sp)
+ return m_type_sp->GetClangForwardType().GetDisplayTypeName();
+ return m_clang_type.GetDisplayTypeName();
+}
+
size_t
ValueObjectMemory::CalculateNumChildren()
{
diff --git a/source/Core/ValueObjectRegister.cpp b/source/Core/ValueObjectRegister.cpp
index 4f21457519ec..0db1f0cd45cf 100644
--- a/source/Core/ValueObjectRegister.cpp
+++ b/source/Core/ValueObjectRegister.cpp
@@ -55,6 +55,12 @@ ValueObjectRegisterContext::GetTypeName()
}
ConstString
+ValueObjectRegisterContext::GetDisplayTypeName()
+{
+ return ConstString();
+}
+
+ConstString
ValueObjectRegisterContext::GetQualifiedTypeName()
{
return ConstString();
diff --git a/source/Core/ValueObjectSyntheticFilter.cpp b/source/Core/ValueObjectSyntheticFilter.cpp
index a65b8f63e317..18d36164989a 100644
--- a/source/Core/ValueObjectSyntheticFilter.cpp
+++ b/source/Core/ValueObjectSyntheticFilter.cpp
@@ -101,6 +101,12 @@ ValueObjectSynthetic::GetQualifiedTypeName()
return m_parent->GetQualifiedTypeName();
}
+ConstString
+ValueObjectSynthetic::GetDisplayTypeName()
+{
+ return m_parent->GetDisplayTypeName();
+}
+
size_t
ValueObjectSynthetic::CalculateNumChildren()
{
diff --git a/source/Core/ValueObjectVariable.cpp b/source/Core/ValueObjectVariable.cpp
index 2e5bb22a890c..225dc02c8add 100644
--- a/source/Core/ValueObjectVariable.cpp
+++ b/source/Core/ValueObjectVariable.cpp
@@ -73,6 +73,15 @@ ValueObjectVariable::GetTypeName()
}
ConstString
+ValueObjectVariable::GetDisplayTypeName()
+{
+ Type * var_type = m_variable_sp->GetType();
+ if (var_type)
+ return var_type->GetClangForwardType().GetDisplayTypeName();
+ return ConstString();
+}
+
+ConstString
ValueObjectVariable::GetQualifiedTypeName()
{
Type * var_type = m_variable_sp->GetType();
diff --git a/source/DataFormatters/CF.cpp b/source/DataFormatters/CF.cpp
index a4b7a1235ffa..e131b68096fd 100644
--- a/source/DataFormatters/CF.cpp
+++ b/source/DataFormatters/CF.cpp
@@ -85,7 +85,7 @@ lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& str
ValueObjectSP count_sp;
StreamString expr;
expr.Printf("(int)CFBagGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
- if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted)
+ if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExpressionCompleted)
return false;
if (!count_sp)
return false;
@@ -160,7 +160,7 @@ lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Strea
if (error.Fail() || num_bytes == 0)
return false;
uint8_t *bytes = buffer_sp->GetBytes();
- for (int byte_idx = 0; byte_idx < num_bytes-1; byte_idx++)
+ for (uint64_t byte_idx = 0; byte_idx < num_bytes-1; byte_idx++)
{
uint8_t byte = bytes[byte_idx];
bool bit0 = (byte & 1) == 1;
@@ -279,7 +279,7 @@ lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stre
ValueObjectSP count_sp;
StreamString expr;
expr.Printf("(int)CFBinaryHeapGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
- if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted)
+ if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExpressionCompleted)
return false;
if (!count_sp)
return false;
diff --git a/source/DataFormatters/CXXFormatterFunctions.cpp b/source/DataFormatters/CXXFormatterFunctions.cpp
index 136c8c51e660..ae5b35fd2b1c 100644
--- a/source/DataFormatters/CXXFormatterFunctions.cpp
+++ b/source/DataFormatters/CXXFormatterFunctions.cpp
@@ -20,8 +20,8 @@
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
-#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
#include <algorithm>
@@ -29,6 +29,23 @@ using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
+StackFrame*
+lldb_private::formatters::GetViableFrame (ExecutionContext exe_ctx)
+{
+ StackFrame* frame = exe_ctx.GetFramePtr();
+ if (frame)
+ return frame;
+
+ Process* process = exe_ctx.GetProcessPtr();
+ if (!process)
+ return nullptr;
+
+ ThreadSP thread_sp(process->GetThreadList().GetSelectedThread());
+ if (thread_sp)
+ return thread_sp->GetSelectedFrame().get();
+ return nullptr;
+}
+
bool
lldb_private::formatters::ExtractValueFromObjCExpression (ValueObject &valobj,
const char* target_type,
@@ -44,7 +61,7 @@ lldb_private::formatters::ExtractValueFromObjCExpression (ValueObject &valobj,
ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
lldb::ValueObjectSP result_sp;
Target* target = exe_ctx.GetTargetPtr();
- StackFrame* stack_frame = exe_ctx.GetFramePtr();
+ StackFrame* stack_frame = GetViableFrame(exe_ctx);
if (!target || !stack_frame)
return false;
@@ -78,7 +95,7 @@ lldb_private::formatters::ExtractSummaryFromObjCExpression (ValueObject &valobj,
ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
lldb::ValueObjectSP result_sp;
Target* target = exe_ctx.GetTargetPtr();
- StackFrame* stack_frame = exe_ctx.GetFramePtr();
+ StackFrame* stack_frame = GetViableFrame(exe_ctx);
if (!target || !stack_frame)
return false;
@@ -116,7 +133,7 @@ lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
lldb::ValueObjectSP result_sp;
Target* target = exe_ctx.GetTargetPtr();
- StackFrame* stack_frame = exe_ctx.GetFramePtr();
+ StackFrame* stack_frame = GetViableFrame(exe_ctx);
if (!target || !stack_frame)
return valobj_sp;
@@ -153,7 +170,7 @@ lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
lldb::ValueObjectSP result_sp;
Target* target = exe_ctx.GetTargetPtr();
- StackFrame* stack_frame = exe_ctx.GetFramePtr();
+ StackFrame* stack_frame = GetViableFrame(exe_ctx);
if (!target || !stack_frame)
return valobj_sp;
@@ -576,7 +593,11 @@ bool
lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream)
{
DataExtractor data;
- valobj.GetData(data);
+ Error error;
+ valobj.GetData(data, error);
+
+ if (error.Fail())
+ return false;
std::string value;
valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
@@ -590,7 +611,11 @@ bool
lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream)
{
DataExtractor data;
- valobj.GetData(data);
+ Error error;
+ valobj.GetData(data, error);
+
+ if (error.Fail())
+ return false;
std::string value;
valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
@@ -604,7 +629,11 @@ bool
lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream)
{
DataExtractor data;
- valobj.GetData(data);
+ Error error;
+ valobj.GetData(data, error);
+
+ if (error.Fail())
+ return false;
clang::ASTContext* ast = valobj.GetClangType().GetASTContext();
@@ -954,6 +983,61 @@ ReadAsciiBufferAndDumpToStream (lldb::addr_t location,
}
bool
+lldb_private::formatters::NSTaggedString_SummaryProvider (ObjCLanguageRuntime::ClassDescriptorSP descriptor, Stream& stream)
+{
+ if (!descriptor)
+ return false;
+ uint64_t len_bits = 0, data_bits = 0;
+ if (!descriptor->GetTaggedPointerInfo(&len_bits,&data_bits,nullptr))
+ return false;
+
+ static const int g_MaxNonBitmaskedLen = 7; //TAGGED_STRING_UNPACKED_MAXLEN
+ static const int g_SixbitMaxLen = 9;
+ static const int g_fiveBitMaxLen = 11;
+
+ static const char *sixBitToCharLookup = "eilotrm.apdnsIc ufkMShjTRxgC4013" "bDNvwyUL2O856P-B79AFKEWV_zGJ/HYX";
+
+ if (len_bits > g_fiveBitMaxLen)
+ return false;
+
+ // this is a fairly ugly trick - pretend that the numeric value is actually a char*
+ // this works under a few assumptions:
+ // little endian architecture
+ // sizeof(uint64_t) > g_MaxNonBitmaskedLen
+ if (len_bits <= g_MaxNonBitmaskedLen)
+ {
+ stream.Printf("@\"%s\"",(const char*)&data_bits);
+ return true;
+ }
+
+ // if the data is bitmasked, we need to actually process the bytes
+ uint8_t bitmask = 0;
+ uint8_t shift_offset = 0;
+
+ if (len_bits <= g_SixbitMaxLen)
+ {
+ bitmask = 0x03f;
+ shift_offset = 6;
+ }
+ else
+ {
+ bitmask = 0x01f;
+ shift_offset = 5;
+ }
+
+ std::vector<uint8_t> bytes;
+ bytes.resize(len_bits);
+ for (; len_bits > 0; data_bits >>= shift_offset, --len_bits)
+ {
+ uint8_t packed = data_bits & bitmask;
+ bytes.insert(bytes.begin(), sixBitToCharLookup[packed]);
+ }
+
+ stream.Printf("@\"%s\"",&bytes[0]);
+ return true;
+}
+
+bool
lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream)
{
ProcessSP process_sp = valobj.GetProcessSP();
@@ -982,6 +1066,12 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
if (!class_name || !*class_name)
return false;
+ bool is_tagged_ptr = (0 == strcmp(class_name,"NSTaggedPointerString")) && descriptor->GetTaggedPointerInfo();
+ // for a tagged pointer, the descriptor has everything we need
+ if (is_tagged_ptr)
+ return NSTaggedString_SummaryProvider(descriptor, stream);
+
+ // if not a tagged pointer that we know about, try the normal route
uint64_t info_bits_location = valobj_addr + ptr_size;
if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
info_bits_location += 3;
@@ -1144,7 +1234,10 @@ lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj
if (!child_ptr_sp)
return false;
DataExtractor data;
- child_ptr_sp->GetData(data);
+ Error error;
+ child_ptr_sp->GetData(data, error);
+ if (error.Fail())
+ return false;
ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type));
child_sp->GetValueAsUnsigned(0);
if (child_sp)
@@ -1218,7 +1311,10 @@ lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& s
else
{
DataExtractor data;
- valobj.GetData(data);
+ Error error;
+ valobj.GetData(data, error);
+ if (error.Fail())
+ return false;
valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
}
diff --git a/source/DataFormatters/Cocoa.cpp b/source/DataFormatters/Cocoa.cpp
index 555954db0bb7..8e92de4ddaa4 100644
--- a/source/DataFormatters/Cocoa.cpp
+++ b/source/DataFormatters/Cocoa.cpp
@@ -342,8 +342,7 @@ lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream&
stream.Printf("(long)%" PRId64,value);
break;
default:
- stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64,i_bits,value);
- break;
+ return false;
}
return true;
}
@@ -402,8 +401,7 @@ lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream&
break;
}
default:
- stream.Printf("unexpected value: dt=%d",data_type);
- break;
+ return false;
}
return true;
}
diff --git a/source/DataFormatters/FormatManager.cpp b/source/DataFormatters/FormatManager.cpp
index 751e61284610..28d108f2410a 100644
--- a/source/DataFormatters/FormatManager.cpp
+++ b/source/DataFormatters/FormatManager.cpp
@@ -21,6 +21,7 @@
#include "lldb/Interpreter/ScriptInterpreterPython.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Platform.h"
+#include "llvm/ADT/STLExtras.h"
using namespace lldb;
using namespace lldb_private;
@@ -76,8 +77,7 @@ g_format_infos[] =
{ eFormatVoid , 'v' , "void" }
};
-static uint32_t
-g_num_format_infos = sizeof(g_format_infos)/sizeof(FormatInfo);
+static uint32_t g_num_format_infos = llvm::array_lengthof(g_format_infos);
static bool
GetFormatFromFormatChar (char format_char, Format &format)
@@ -186,7 +186,11 @@ FormatManager::GetPossibleMatches (ValueObject& valobj,
}
entries.push_back({type_name,reason,did_strip_ptr,did_strip_ref,did_strip_typedef});
- if (clang_type.IsReferenceType())
+ ConstString display_type_name(clang_type.GetDisplayTypeName());
+ if (display_type_name != type_name)
+ entries.push_back({display_type_name,reason,did_strip_ptr,did_strip_ref,did_strip_typedef});
+
+ for (bool is_rvalue_ref = true, j = true; j && clang_type.IsReferenceType(nullptr, &is_rvalue_ref); j = false)
{
ClangASTType non_ref_type = clang_type.GetNonReferenceType();
GetPossibleMatches(valobj,
@@ -197,8 +201,22 @@ FormatManager::GetPossibleMatches (ValueObject& valobj,
did_strip_ptr,
true,
did_strip_typedef);
+ if (non_ref_type.IsTypedefType())
+ {
+ ClangASTType deffed_referenced_type = non_ref_type.GetTypedefedType();
+ deffed_referenced_type = is_rvalue_ref ? deffed_referenced_type.GetRValueReferenceType() : deffed_referenced_type.GetLValueReferenceType();
+ GetPossibleMatches(valobj,
+ deffed_referenced_type,
+ reason | lldb_private::eFormatterChoiceCriterionNavigatedTypedefs,
+ use_dynamic,
+ entries,
+ did_strip_ptr,
+ did_strip_ref,
+ true); // this is not exactly the usual meaning of stripping typedefs
+ }
}
- else if (clang_type.IsPointerType())
+
+ if (clang_type.IsPointerType())
{
ClangASTType non_ptr_type = clang_type.GetPointeeType();
GetPossibleMatches(valobj,
@@ -209,6 +227,18 @@ FormatManager::GetPossibleMatches (ValueObject& valobj,
true,
did_strip_ref,
did_strip_typedef);
+ if (non_ptr_type.IsTypedefType())
+ {
+ ClangASTType deffed_pointed_type = non_ptr_type.GetTypedefedType().GetPointerType();
+ GetPossibleMatches(valobj,
+ deffed_pointed_type,
+ reason | lldb_private::eFormatterChoiceCriterionNavigatedTypedefs,
+ use_dynamic,
+ entries,
+ did_strip_ptr,
+ did_strip_ref,
+ true); // this is not exactly the usual meaning of stripping typedefs
+ }
}
bool canBeObjCDynamic = clang_type.IsPossibleDynamicType (NULL,
false, // no C
@@ -507,7 +537,7 @@ FormatManager::ShouldPrintAsOneLiner (ValueObject& valobj)
if (child_sp->GetSummaryFormat())
{
// and it wants children, then bail out
- if (child_sp->GetSummaryFormat()->DoesPrintChildren())
+ if (child_sp->GetSummaryFormat()->DoesPrintChildren(child_sp.get()))
return false;
}
@@ -553,11 +583,17 @@ GetTypeForCache (ValueObject& valobj,
return ConstString();
}
-static lldb::TypeFormatImplSP
-GetHardcodedFormat (ValueObject& valobj,
- lldb::DynamicValueType use_dynamic)
+lldb::TypeFormatImplSP
+FormatManager::GetHardcodedFormat (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic)
{
- return lldb::TypeFormatImplSP();
+ for (const auto& candidate: m_hardcoded_formats)
+ {
+ auto result = candidate(valobj,use_dynamic,*this);
+ if (result)
+ return result;
+ }
+ return nullptr;
}
lldb::TypeFormatImplSP
@@ -591,10 +627,12 @@ FormatManager::GetFormat (ValueObject& valobj,
log->Printf("[FormatManager::GetFormat] Search failed. Giving hardcoded a chance.");
retval = GetHardcodedFormat(valobj, use_dynamic);
}
- if (valobj_type)
+ else if (valobj_type)
{
if (log)
- log->Printf("[FormatManager::GetFormat] Caching %p for type %s",retval.get(),valobj_type.AsCString("<invalid>"));
+ log->Printf("[FormatManager::GetFormat] Caching %p for type %s",
+ static_cast<void*>(retval.get()),
+ valobj_type.AsCString("<invalid>"));
m_format_cache.SetFormat(valobj_type,retval);
}
if (log && log->GetDebug())
@@ -602,11 +640,17 @@ FormatManager::GetFormat (ValueObject& valobj,
return retval;
}
-static lldb::TypeSummaryImplSP
-GetHardcodedSummaryFormat (ValueObject& valobj,
- lldb::DynamicValueType use_dynamic)
+lldb::TypeSummaryImplSP
+FormatManager::GetHardcodedSummaryFormat (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic)
{
- return lldb::TypeSummaryImplSP();
+ for (const auto& candidate: m_hardcoded_summaries)
+ {
+ auto result = candidate(valobj,use_dynamic,*this);
+ if (result)
+ return result;
+ }
+ return nullptr;
}
lldb::TypeSummaryImplSP
@@ -640,10 +684,12 @@ FormatManager::GetSummaryFormat (ValueObject& valobj,
log->Printf("[FormatManager::GetSummaryFormat] Search failed. Giving hardcoded a chance.");
retval = GetHardcodedSummaryFormat(valobj, use_dynamic);
}
- if (valobj_type)
+ else if (valobj_type)
{
if (log)
- log->Printf("[FormatManager::GetSummaryFormat] Caching %p for type %s",retval.get(),valobj_type.AsCString("<invalid>"));
+ log->Printf("[FormatManager::GetSummaryFormat] Caching %p for type %s",
+ static_cast<void*>(retval.get()),
+ valobj_type.AsCString("<invalid>"));
m_format_cache.SetSummary(valobj_type,retval);
}
if (log && log->GetDebug())
@@ -652,11 +698,17 @@ FormatManager::GetSummaryFormat (ValueObject& valobj,
}
#ifndef LLDB_DISABLE_PYTHON
-static lldb::SyntheticChildrenSP
-GetHardcodedSyntheticChildren (ValueObject& valobj,
- lldb::DynamicValueType use_dynamic)
+lldb::SyntheticChildrenSP
+FormatManager::GetHardcodedSyntheticChildren (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic)
{
- return lldb::SyntheticChildrenSP();
+ for (const auto& candidate: m_hardcoded_synthetics)
+ {
+ auto result = candidate(valobj,use_dynamic,*this);
+ if (result)
+ return result;
+ }
+ return nullptr;
}
lldb::SyntheticChildrenSP
@@ -690,10 +742,12 @@ FormatManager::GetSyntheticChildren (ValueObject& valobj,
log->Printf("[FormatManager::GetSyntheticChildren] Search failed. Giving hardcoded a chance.");
retval = GetHardcodedSyntheticChildren(valobj, use_dynamic);
}
- if (valobj_type)
+ else if (valobj_type)
{
if (log)
- log->Printf("[FormatManager::GetSyntheticChildren] Caching %p for type %s",retval.get(),valobj_type.AsCString("<invalid>"));
+ log->Printf("[FormatManager::GetSyntheticChildren] Caching %p for type %s",
+ static_cast<void*>(retval.get()),
+ valobj_type.AsCString("<invalid>"));
m_format_cache.SetSynthetic(valobj_type,retval);
}
if (log && log->GetDebug())
@@ -716,12 +770,17 @@ FormatManager::FormatManager() :
m_coregraphics_category_name(ConstString("CoreGraphics")),
m_coreservices_category_name(ConstString("CoreServices")),
m_vectortypes_category_name(ConstString("VectorTypes")),
- m_appkit_category_name(ConstString("AppKit"))
+ m_appkit_category_name(ConstString("AppKit")),
+ m_hardcoded_formats(),
+ m_hardcoded_summaries(),
+ m_hardcoded_synthetics()
+
{
LoadSystemFormatters();
LoadLibStdcppFormatters();
LoadLibcxxFormatters();
LoadObjCFormatters();
+ LoadHardcodedFormatters();
EnableCategory(m_objc_category_name,TypeCategoryMap::Last);
EnableCategory(m_corefoundation_category_name,TypeCategoryMap::Last);
@@ -768,28 +827,6 @@ AddStringSummary(TypeCategoryImpl::SharedPointer category_sp,
#ifndef LLDB_DISABLE_PYTHON
static void
-AddScriptSummary(TypeCategoryImpl::SharedPointer category_sp,
- const char* funct_name,
- ConstString type_name,
- TypeSummaryImpl::Flags flags,
- bool regex = false)
-{
-
- std::string code(" ");
- code.append(funct_name).append("(valobj,internal_dict)");
-
- lldb::TypeSummaryImplSP summary_sp(new ScriptSummaryFormat(flags,
- funct_name,
- code.c_str()));
- if (regex)
- category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp);
- else
- category_sp->GetTypeSummariesContainer()->Add(type_name, summary_sp);
-}
-#endif
-
-#ifndef LLDB_DISABLE_PYTHON
-static void
AddCXXSummary (TypeCategoryImpl::SharedPointer category_sp,
CXXFunctionSummaryFormat::Callback funct,
const char* description,
@@ -956,6 +993,7 @@ FormatManager::LoadLibcxxFormatters()
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator, "libc++ std::list synthetic children", ConstString("^std::__1::list<.+>(( )?&)?$"), stl_synth_flags, true);
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::map synthetic children", ConstString("^std::__1::map<.+> >(( )?&)?$"), stl_synth_flags, true);
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator, "libc++ std::vector<bool> synthetic children", ConstString("std::__1::vector<std::__1::allocator<bool> >"), stl_synth_flags);
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator, "libc++ std::vector<bool> synthetic children", ConstString("std::__1::vector<bool, std::__1::allocator<bool> >"), stl_synth_flags);
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::set synthetic children", ConstString("^std::__1::set<.+> >(( )?&)?$"), stl_synth_flags, true);
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multiset synthetic children", ConstString("^std::__1::multiset<.+> >(( )?&)?$"), stl_synth_flags, true);
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multimap synthetic children", ConstString("^std::__1::multimap<.+> >(( )?&)?$"), stl_synth_flags, true);
@@ -969,12 +1007,14 @@ FormatManager::LoadLibcxxFormatters()
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, "weak_ptr synthetic children", ConstString("^(std::__1::)weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
stl_summary_flags.SetDontShowChildren(false);stl_summary_flags.SetSkipPointers(false);
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator, "libc++ std::vector<bool> synthetic children", ConstString("std::__1::vector<bool, std::__1::allocator<bool> >"), stl_synth_flags);
AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector summary provider", ConstString("^std::__1::vector<.+>(( )?&)?$"), stl_summary_flags, true);
AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::list summary provider", ConstString("^std::__1::list<.+>(( )?&)?$"), stl_summary_flags, true);
AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::map summary provider", ConstString("^std::__1::map<.+>(( )?&)?$"), stl_summary_flags, true);
AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::deque summary provider", ConstString("^std::__1::deque<.+>(( )?&)?$"), stl_summary_flags, true);
AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector<bool> summary provider", ConstString("std::__1::vector<std::__1::allocator<bool> >"), stl_summary_flags);
+ AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector<bool> summary provider", ConstString("std::__1::vector<bool, std::__1::allocator<bool> >"), stl_summary_flags);
AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::set summary provider", ConstString("^std::__1::set<.+>(( )?&)?$"), stl_summary_flags, true);
AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::multiset summary provider", ConstString("^std::__1::multiset<.+>(( )?&)?$"), stl_summary_flags, true);
AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::multimap summary provider", ConstString("^std::__1::multimap<.+>(( )?&)?$"), stl_summary_flags, true);
@@ -987,6 +1027,7 @@ FormatManager::LoadLibcxxFormatters()
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^std::__1::__wrap_iter<.+>$"), stl_synth_flags, true);
+ AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector<bool> summary provider", ConstString("std::__1::vector<bool, std::__1::allocator<bool> >"), stl_summary_flags);
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::__1::__map_iterator<.+>$"), stl_synth_flags, true);
AddFilter(libcxx_category_sp, {"__a_"}, "libc++ std::atomic filter", ConstString("^std::__1::atomic<.*>$"), stl_synth_flags, true);
@@ -1253,6 +1294,7 @@ FormatManager::LoadObjCFormatters()
AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", ConstString("__NSDictionaryM"), ScriptedSyntheticChildren::Flags());
AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", ConstString("__NSDictionaryI"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", ConstString("__NSCFDictionary"), ScriptedSyntheticChildren::Flags());
AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", ConstString("NSDictionary"), ScriptedSyntheticChildren::Flags());
AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", ConstString("NSMutableDictionary"), ScriptedSyntheticChildren::Flags());
AddCXXSynthetic(corefoundation_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", ConstString("CFDictionaryRef"), ScriptedSyntheticChildren::Flags());
@@ -1294,6 +1336,7 @@ FormatManager::LoadObjCFormatters()
AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>, "NSData summary provider", ConstString("NSData"), appkit_flags);
AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>, "NSData summary provider", ConstString("NSConcreteData"), appkit_flags);
AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>, "NSData summary provider", ConstString("NSConcreteMutableData"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>, "NSData summary provider", ConstString("NSMutableData"), appkit_flags);
AddCXXSummary(corefoundation_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>, "NSData summary provider", ConstString("__NSCFData"), appkit_flags);
AddCXXSummary(corefoundation_category_sp, lldb_private::formatters::NSDataSummaryProvider<true>, "NSData summary provider", ConstString("CFDataRef"), appkit_flags);
AddCXXSummary(corefoundation_category_sp, lldb_private::formatters::NSDataSummaryProvider<true>, "NSData summary provider", ConstString("CFMutableDataRef"), appkit_flags);
@@ -1419,3 +1462,17 @@ FormatManager::LoadObjCFormatters()
ConstString("vBool32"),
vector_flags);
}
+
+void
+FormatManager::LoadHardcodedFormatters()
+{
+ {
+ // insert code to load formats here
+ }
+ {
+ // insert code to load summaries here
+ }
+ {
+ // insert code to load synthetics here
+ }
+}
diff --git a/source/DataFormatters/LibCxx.cpp b/source/DataFormatters/LibCxx.cpp
index 6380d971a177..174202661f03 100644
--- a/source/DataFormatters/LibCxx.cpp
+++ b/source/DataFormatters/LibCxx.cpp
@@ -139,13 +139,11 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex (si
return ValueObjectSP();
}
bool bit_set = ((byte & mask) != 0);
- ValueObjectSP retval_sp;
DataBufferSP buffer_sp(new DataBufferHeap(m_bool_type.GetByteSize(),0));
if (bit_set && buffer_sp && buffer_sp->GetBytes())
*(buffer_sp->GetBytes()) = 1; // regardless of endianness, anything non-zero is true
- StreamString name; name.Printf("[%zu]",idx);
- DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
- retval_sp = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_exe_ctx_ref, m_bool_type);
+ StreamString name; name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ ValueObjectSP retval_sp(ValueObject::CreateValueObjectFromData(name.GetData(), DataExtractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()), m_exe_ctx_ref, m_bool_type));
if (retval_sp)
m_children[idx] = retval_sp;
return retval_sp;
@@ -168,8 +166,6 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update()
ValueObjectSP valobj_sp = m_backend.GetSP();
if (!valobj_sp)
return false;
- if (!valobj_sp)
- return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName(ConstString("__size_"), true));
if (!size_sp)
@@ -499,7 +495,7 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex (siz
uint64_t offset = idx * m_element_size;
offset = offset + m_start->GetValueAsUnsigned(0);
StreamString name;
- name.Printf("[%zu]",idx);
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
ValueObjectSP child_sp = ValueObject::CreateValueObjectFromAddress(name.GetData(), offset, m_backend.GetExecutionContextRef(), m_element_type);
m_children[idx] = child_sp;
return child_sp;
diff --git a/source/DataFormatters/LibCxxList.cpp b/source/DataFormatters/LibCxxList.cpp
index de2ca1b20459..7d6db1a0ccd4 100644
--- a/source/DataFormatters/LibCxxList.cpp
+++ b/source/DataFormatters/LibCxxList.cpp
@@ -33,20 +33,20 @@ public:
ListEntry (const ListEntry& rhs) : m_entry_sp(rhs.m_entry_sp) {}
ListEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
- ValueObjectSP
+ ListEntry
next ()
{
if (!m_entry_sp)
- return m_entry_sp;
- return m_entry_sp->GetChildMemberWithName(ConstString("__next_"), true);
+ return ListEntry();
+ return ListEntry(m_entry_sp->GetChildMemberWithName(ConstString("__next_"), true));
}
- ValueObjectSP
+ ListEntry
prev ()
{
if (!m_entry_sp)
- return m_entry_sp;
- return m_entry_sp->GetChildMemberWithName(ConstString("__prev_"), true);
+ return ListEntry();
+ return ListEntry(m_entry_sp->GetChildMemberWithName(ConstString("__prev_"), true));
}
uint64_t
@@ -63,6 +63,11 @@ public:
return (value() == 0);
}
+ explicit operator bool ()
+ {
+ return GetEntry().get() != nullptr && null() == false;
+ }
+
ValueObjectSP
GetEntry ()
{
@@ -130,13 +135,13 @@ protected:
void
next ()
{
- m_entry.SetEntry(m_entry.next());
+ m_entry = m_entry.next();
}
void
prev ()
{
- m_entry.SetEntry(m_entry.prev());
+ m_entry = m_entry.prev();
}
private:
ListEntry m_entry;
@@ -161,17 +166,24 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop()
{
if (g_use_loop_detect == false)
return false;
+ // don't bother checking for a loop if we won't actually need to jump nodes
+ if (m_count < 2)
+ return false;
+ auto steps_left = m_count;
ListEntry slow(m_head);
- ListEntry fast1(m_head);
- ListEntry fast2(m_head);
- while (slow.next() && slow.next()->GetValueAsUnsigned(0) != m_node_address)
+ ListEntry fast(m_head);
+ while (steps_left-- > 0)
{
- auto slow_value = slow.value();
- fast1.SetEntry(fast2.next());
- fast2.SetEntry(fast1.next());
- if (fast1.value() == slow_value || fast2.value() == slow_value)
+ slow = slow.next();
+ fast = fast.next();
+ if (fast.next())
+ fast = fast.next().next();
+ else
+ fast = nullptr;
+ if (!slow || !fast)
+ return false;
+ if (slow == fast)
return true;
- slow.SetEntry(slow.next());
}
return false;
}
@@ -212,10 +224,10 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::CalculateNumChildren (
return 0;
uint64_t size = 2;
ListEntry current(m_head);
- while (current.next() && current.next()->GetValueAsUnsigned(0) != m_node_address)
+ while (current.next() && current.next().value() != m_node_address)
{
size++;
- current.SetEntry(current.next());
+ current = current.next();
if (size > m_list_capping_size)
break;
}
@@ -245,9 +257,13 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_
return lldb::ValueObjectSP();
// we need to copy current_sp into a new object otherwise we will end up with all items named __value_
DataExtractor data;
- current_sp->GetData(data);
+ Error error;
+ current_sp->GetData(data, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+
StreamString name;
- name.Printf("[%zu]",idx);
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
return (m_children[idx] = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type));
}
diff --git a/source/DataFormatters/LibCxxMap.cpp b/source/DataFormatters/LibCxxMap.cpp
index 5daa40f15f3d..e665f29622d8 100644
--- a/source/DataFormatters/LibCxxMap.cpp
+++ b/source/DataFormatters/LibCxxMap.cpp
@@ -366,9 +366,15 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex (size_t
// at this point we have a valid
// we need to copy current_sp into a new object otherwise we will end up with all items named __value_
DataExtractor data;
- iterated_sp->GetData(data);
+ Error error;
+ iterated_sp->GetData(data, error);
+ if (error.Fail())
+ {
+ m_tree = NULL;
+ return lldb::ValueObjectSP();
+ }
StreamString name;
- name.Printf("[%zu]",idx);
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
return (m_children[idx] = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type));
}
diff --git a/source/DataFormatters/LibCxxUnorderedMap.cpp b/source/DataFormatters/LibCxxUnorderedMap.cpp
index 05b41d0de0c8..bf68f20955b5 100644
--- a/source/DataFormatters/LibCxxUnorderedMap.cpp
+++ b/source/DataFormatters/LibCxxUnorderedMap.cpp
@@ -81,9 +81,12 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtInde
if (!val_hash.first)
return lldb::ValueObjectSP();
StreamString stream;
- stream.Printf("[%zu]",idx);
+ stream.Printf("[%" PRIu64 "]", (uint64_t)idx);
DataExtractor data;
- val_hash.first->GetData(data);
+ Error error;
+ val_hash.first->GetData(data, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
const bool thread_and_frame_only_if_stopped = true;
ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped);
return val_hash.first->CreateValueObjectFromData(stream.GetData(),
diff --git a/source/DataFormatters/LibStdcpp.cpp b/source/DataFormatters/LibStdcpp.cpp
index 08e7d584003e..f2d617323cca 100644
--- a/source/DataFormatters/LibStdcpp.cpp
+++ b/source/DataFormatters/LibStdcpp.cpp
@@ -93,7 +93,7 @@ lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::GetChildAtIndex
target.EvaluateExpression("(bool)true", NULL, retval_sp);
else
target.EvaluateExpression("(bool)false", NULL, retval_sp);
- StreamString name; name.Printf("[%zu]",idx);
+ StreamString name; name.Printf("[%" PRIu64 "]", (uint64_t)idx);
if (retval_sp)
retval_sp->SetName(ConstString(name.GetData()));
return retval_sp;
diff --git a/source/DataFormatters/NSArray.cpp b/source/DataFormatters/NSArray.cpp
index d8ee9bfa8a47..16635381f94f 100644
--- a/source/DataFormatters/NSArray.cpp
+++ b/source/DataFormatters/NSArray.cpp
@@ -19,12 +19,214 @@
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
#include "lldb/Target/Target.h"
+#include "clang/AST/ASTContext.h"
+
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
+namespace lldb_private {
+ namespace formatters {
+ class NSArrayMSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update() = 0;
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~NSArrayMSyntheticFrontEnd () {}
+
+ protected:
+ virtual lldb::addr_t
+ GetDataAddress () = 0;
+
+ virtual uint64_t
+ GetUsedCount () = 0;
+
+ virtual uint64_t
+ GetOffset () = 0;
+
+ virtual uint64_t
+ GetSize () = 0;
+
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+ ClangASTType m_id_type;
+ std::vector<lldb::ValueObjectSP> m_children;
+ };
+
+ class NSArrayMSyntheticFrontEnd_109 : public NSArrayMSyntheticFrontEnd
+ {
+ private:
+ struct DataDescriptor_32
+ {
+ uint32_t _used;
+ uint32_t _priv1 : 2 ;
+ uint32_t _size : 30;
+ uint32_t _priv2 : 2;
+ uint32_t _offset : 30;
+ uint32_t _priv3;
+ uint32_t _data;
+ };
+ struct DataDescriptor_64
+ {
+ uint64_t _used;
+ uint64_t _priv1 : 2 ;
+ uint64_t _size : 62;
+ uint64_t _priv2 : 2;
+ uint64_t _offset : 62;
+ uint32_t _priv3;
+ uint64_t _data;
+ };
+ public:
+ NSArrayMSyntheticFrontEnd_109 (lldb::ValueObjectSP valobj_sp);
+
+ virtual bool
+ Update();
+
+ virtual
+ ~NSArrayMSyntheticFrontEnd_109 ();
+
+ protected:
+ virtual lldb::addr_t
+ GetDataAddress ();
+
+ virtual uint64_t
+ GetUsedCount ();
+
+ virtual uint64_t
+ GetOffset ();
+
+ virtual uint64_t
+ GetSize ();
+
+ private:
+ DataDescriptor_32 *m_data_32;
+ DataDescriptor_64 *m_data_64;
+ };
+
+ class NSArrayMSyntheticFrontEnd_1010 : public NSArrayMSyntheticFrontEnd
+ {
+ private:
+ struct DataDescriptor_32
+ {
+ uint32_t _used;
+ uint32_t _offset;
+ uint32_t _size : 28;
+ uint64_t _priv1 : 4;
+ uint32_t _priv2;
+ uint32_t _data;
+ };
+ struct DataDescriptor_64
+ {
+ uint64_t _used;
+ uint64_t _offset;
+ uint64_t _size : 60;
+ uint64_t _priv1 : 4;
+ uint32_t _priv2;
+ uint64_t _data;
+ };
+ public:
+ NSArrayMSyntheticFrontEnd_1010 (lldb::ValueObjectSP valobj_sp);
+
+ virtual bool
+ Update();
+
+ virtual
+ ~NSArrayMSyntheticFrontEnd_1010 ();
+
+ protected:
+ virtual lldb::addr_t
+ GetDataAddress ();
+
+ virtual uint64_t
+ GetUsedCount ();
+
+ virtual uint64_t
+ GetOffset ();
+
+ virtual uint64_t
+ GetSize ();
+
+ private:
+ DataDescriptor_32 *m_data_32;
+ DataDescriptor_64 *m_data_64;
+ };
+
+ class NSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~NSArrayISyntheticFrontEnd ();
+ private:
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+ uint64_t m_items;
+ lldb::addr_t m_data_ptr;
+ ClangASTType m_id_type;
+ std::vector<lldb::ValueObjectSP> m_children;
+ };
+
+ class NSArrayCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~NSArrayCodeRunningSyntheticFrontEnd ();
+ };
+ }
+}
+
bool
lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream)
{
@@ -90,45 +292,55 @@ lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& s
}
lldb_private::formatters::NSArrayMSyntheticFrontEnd::NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
- SyntheticChildrenFrontEnd(*valobj_sp.get()),
+SyntheticChildrenFrontEnd(*valobj_sp),
m_exe_ctx_ref(),
m_ptr_size(8),
- m_data_32(NULL),
- m_data_64(NULL)
+m_id_type(),
+m_children()
{
if (valobj_sp)
{
- clang::ASTContext *ast = valobj_sp->GetClangType().GetASTContext();
+ clang::ASTContext *ast = valobj_sp->GetExecutionContextRef().GetTargetSP()->GetScratchClangASTContext()->getASTContext();
if (ast)
m_id_type = ClangASTType(ast, ast->ObjCBuiltinIdTy);
+ if (valobj_sp->GetProcessSP())
+ m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize();
}
}
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::NSArrayMSyntheticFrontEnd_109 (lldb::ValueObjectSP valobj_sp) :
+NSArrayMSyntheticFrontEnd(valobj_sp),
+m_data_32(NULL),
+m_data_64(NULL)
+{
+}
+
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::NSArrayMSyntheticFrontEnd_1010 (lldb::ValueObjectSP valobj_sp) :
+NSArrayMSyntheticFrontEnd(valobj_sp),
+m_data_32(NULL),
+m_data_64(NULL)
+{
+}
+
size_t
lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren ()
{
- if (m_data_32)
- return m_data_32->_used;
- if (m_data_64)
- return m_data_64->_used;
- return 0;
+ return GetUsedCount();
}
lldb::ValueObjectSP
lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
- if (!m_data_32 && !m_data_64)
- return lldb::ValueObjectSP();
if (idx >= CalculateNumChildren())
return lldb::ValueObjectSP();
- lldb::addr_t object_at_idx = (m_data_32 ? m_data_32->_data : m_data_64->_data);
+ lldb::addr_t object_at_idx = GetDataAddress();
size_t pyhs_idx = idx;
- pyhs_idx += (m_data_32 ? m_data_32->offset : m_data_64->offset);
- if ((m_data_32 ? m_data_32->_size : m_data_64->_size) <= pyhs_idx)
- pyhs_idx -= (m_data_32 ? m_data_32->_size : m_data_64->_size);
+ pyhs_idx += GetOffset();
+ if (GetSize() <= pyhs_idx)
+ pyhs_idx -= GetSize();
object_at_idx += (pyhs_idx * m_ptr_size);
StreamString idx_name;
- idx_name.Printf("[%zu]",idx);
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(),
object_at_idx,
m_exe_ctx_ref,
@@ -138,7 +350,42 @@ lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx
}
bool
-lldb_private::formatters::NSArrayMSyntheticFrontEnd::Update()
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::Update()
+{
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = NULL;
+ delete m_data_64;
+ m_data_64 = NULL;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Error error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4)
+ {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
+ }
+ else
+ {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
+ }
+ if (error.Fail())
+ return false;
+ return false;
+}
+
+bool
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::Update()
{
m_children.clear();
ValueObjectSP valobj_sp = m_backend.GetSP();
@@ -181,8 +428,6 @@ lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren ()
size_t
lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
{
- if (!m_data_32 && !m_data_64)
- return UINT32_MAX;
const char* item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
if (idx < UINT32_MAX && idx >= CalculateNumChildren())
@@ -190,7 +435,87 @@ lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetIndexOfChildWithName (co
return idx;
}
-lldb_private::formatters::NSArrayMSyntheticFrontEnd::~NSArrayMSyntheticFrontEnd ()
+lldb::addr_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetDataAddress ()
+{
+ if (!m_data_32 && !m_data_64)
+ return LLDB_INVALID_ADDRESS;
+ return m_data_32 ? m_data_32->_data :
+ m_data_64->_data;
+}
+
+uint64_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetUsedCount ()
+{
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->_used :
+ m_data_64->_used;
+}
+
+uint64_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetOffset ()
+{
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->_offset :
+ m_data_64->_offset;
+}
+
+uint64_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetSize ()
+{
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->_size :
+ m_data_64->_size;
+}
+
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::~NSArrayMSyntheticFrontEnd_109 ()
+{
+ delete m_data_32;
+ m_data_32 = NULL;
+ delete m_data_64;
+ m_data_64 = NULL;
+}
+
+lldb::addr_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetDataAddress ()
+{
+ if (!m_data_32 && !m_data_64)
+ return LLDB_INVALID_ADDRESS;
+ return m_data_32 ? m_data_32->_data :
+ m_data_64->_data;
+}
+
+uint64_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetUsedCount ()
+{
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->_used :
+ m_data_64->_used;
+}
+
+uint64_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetOffset ()
+{
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->_offset :
+ m_data_64->_offset;
+}
+
+uint64_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetSize ()
+{
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->_size :
+ m_data_64->_size;
+}
+
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::~NSArrayMSyntheticFrontEnd_1010 ()
{
delete m_data_32;
m_data_32 = NULL;
@@ -278,7 +603,7 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx
if (error.Fail())
return lldb::ValueObjectSP();
StreamString idx_name;
- idx_name.Printf("[%zu]",idx);
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(), object_at_idx, m_exe_ctx_ref, m_id_type);
m_children.push_back(retval_sp);
return retval_sp;
@@ -286,14 +611,20 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx
SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
+ if (!valobj_sp)
+ return nullptr;
+
lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
if (!process_sp)
return NULL;
- ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+ AppleObjCRuntime *runtime = (AppleObjCRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
if (!runtime)
return NULL;
- if (!valobj_sp->IsPointerType())
+ ClangASTType valobj_type(valobj_sp->GetClangType());
+ Flags flags(valobj_type.GetTypeInfo());
+
+ if (flags.IsClear(ClangASTType::eTypeIsPointer))
{
Error error;
valobj_sp = valobj_sp->AddressOf(error);
@@ -317,7 +648,10 @@ SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCre
}
else if (!strcmp(class_name,"__NSArrayM"))
{
- return (new NSArrayMSyntheticFrontEnd(valobj_sp));
+ if (runtime->GetFoundationVersion() >= 1100)
+ return (new NSArrayMSyntheticFrontEnd_1010(valobj_sp));
+ else
+ return (new NSArrayMSyntheticFrontEnd_109(valobj_sp));
}
else
{
@@ -342,7 +676,7 @@ lldb::ValueObjectSP
lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
StreamString idx_name;
- idx_name.Printf("[%zu]",idx);
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
lldb::ValueObjectSP valobj_sp = CallSelectorOnObject(m_backend,"id","objectAtIndex:",idx);
if (valobj_sp)
valobj_sp->SetName(ConstString(idx_name.GetData()));
diff --git a/source/DataFormatters/NSDictionary.cpp b/source/DataFormatters/NSDictionary.cpp
index f53004df5c5f..ddd1e2e7ca90 100644
--- a/source/DataFormatters/NSDictionary.cpp
+++ b/source/DataFormatters/NSDictionary.cpp
@@ -210,9 +210,9 @@ lldb::ValueObjectSP
lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
StreamString idx_name;
- idx_name.Printf("[%zu]",idx);
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
StreamString key_fetcher_expr;
- key_fetcher_expr.Printf("(id)[(NSArray*)[(id)0x%" PRIx64 " allKeys] objectAtIndex:%zu]",m_backend.GetPointerValue(),idx);
+ key_fetcher_expr.Printf("(id)[(NSArray*)[(id)0x%" PRIx64 " allKeys] objectAtIndex:%" PRIu64 "]", m_backend.GetPointerValue(), (uint64_t)idx);
StreamString value_fetcher_expr;
value_fetcher_expr.Printf("(id)[(id)0x%" PRIx64 " objectForKey:(%s)]",m_backend.GetPointerValue(),key_fetcher_expr.GetData());
StreamString object_fetcher_expr;
@@ -220,7 +220,9 @@ lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIn
lldb::ValueObjectSP child_sp;
EvaluateExpressionOptions options;
options.SetKeepInMemory(true);
- m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), m_backend.GetFrameSP().get(), child_sp,
+ m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(),
+ GetViableFrame(m_backend.GetTargetSP().get()),
+ child_sp,
options);
if (child_sp)
child_sp->SetName(ConstString(idx_name.GetData()));
@@ -403,7 +405,7 @@ lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_
}
StreamString idx_name;
- idx_name.Printf("[%zu]",idx);
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
DataExtractor data(buffer_sp, m_order, m_ptr_size);
dict_item.valobj_sp = ValueObject::CreateValueObjectFromData(idx_name.GetData(), data, m_exe_ctx_ref, m_pair_type);
}
@@ -567,7 +569,7 @@ lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_
}
StreamString idx_name;
- idx_name.Printf("[%zu]",idx);
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
DataExtractor data(buffer_sp, m_order, m_ptr_size);
dict_item.valobj_sp = ValueObject::CreateValueObjectFromData(idx_name.GetData(), data, m_exe_ctx_ref, m_pair_type);
}
diff --git a/source/DataFormatters/NSSet.cpp b/source/DataFormatters/NSSet.cpp
index e6fe2a34a67b..3c7c003ed95a 100644
--- a/source/DataFormatters/NSSet.cpp
+++ b/source/DataFormatters/NSSet.cpp
@@ -305,7 +305,7 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex (size_t idx)
assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
}
StreamString idx_name;
- idx_name.Printf("[%zu]",idx);
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
DataExtractor data(buffer.GetBytes(),
buffer.GetByteSize(),
@@ -473,7 +473,7 @@ lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
}
StreamString idx_name;
- idx_name.Printf("[%zu]",idx);
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
DataExtractor data(buffer.GetBytes(),
buffer.GetByteSize(),
@@ -519,7 +519,7 @@ lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::GetChildAtIndex (size_t
if (retval_sp)
{
StreamString idx_name;
- idx_name.Printf("[%zu]",idx);
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
retval_sp->SetName(ConstString(idx_name.GetData()));
}
m_children[idx] = retval_sp;
diff --git a/source/DataFormatters/TypeFormat.cpp b/source/DataFormatters/TypeFormat.cpp
index a72f551c741f..0c62daf87bbc 100644
--- a/source/DataFormatters/TypeFormat.cpp
+++ b/source/DataFormatters/TypeFormat.cpp
@@ -38,6 +38,9 @@ m_my_revision(0)
{
}
+TypeFormatImpl::~TypeFormatImpl ()
+{
+}
TypeFormatImpl_Format::TypeFormatImpl_Format (lldb::Format f,
const TypeFormatImpl::Flags& flags) :
@@ -46,6 +49,10 @@ m_format (f)
{
}
+TypeFormatImpl_Format::~TypeFormatImpl_Format ()
+{
+}
+
bool
TypeFormatImpl_Format::FormatObject (ValueObject *valobj,
std::string& dest) const
@@ -64,7 +71,10 @@ TypeFormatImpl_Format::FormatObject (ValueObject *valobj,
const RegisterInfo *reg_info = value.GetRegisterInfo();
if (reg_info)
{
- valobj->GetData(data);
+ Error error;
+ valobj->GetData(data, error);
+ if (error.Fail())
+ return false;
StreamString reg_sstr;
data.Dump (&reg_sstr,
@@ -105,7 +115,12 @@ TypeFormatImpl_Format::FormatObject (ValueObject *valobj,
}
}
else
- valobj->GetData(data);
+ {
+ Error error;
+ valobj->GetData(data, error);
+ if (error.Fail())
+ return false;
+ }
StreamString sstr;
clang_type.DumpTypeValue (&sstr, // The stream to use for display
@@ -154,6 +169,10 @@ m_types()
{
}
+TypeFormatImpl_EnumType::~TypeFormatImpl_EnumType ()
+{
+}
+
bool
TypeFormatImpl_EnumType::FormatObject (ValueObject *valobj,
std::string& dest) const
@@ -203,7 +222,10 @@ TypeFormatImpl_EnumType::FormatObject (ValueObject *valobj,
if (valobj_enum_type.IsValid() == false)
return false;
DataExtractor data;
- valobj->GetData(data);
+ Error error;
+ valobj->GetData(data, error);
+ if (error.Fail())
+ return false;
ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
StreamString sstr;
valobj_enum_type.DumpTypeValue(&sstr,
diff --git a/source/DataFormatters/TypeSummary.cpp b/source/DataFormatters/TypeSummary.cpp
index 4c75b4b87d03..e5d80174c3cc 100644
--- a/source/DataFormatters/TypeSummary.cpp
+++ b/source/DataFormatters/TypeSummary.cpp
@@ -69,7 +69,7 @@ StringSummaryFormat::FormatObject (ValueObject *valobj,
if (IsOneLiner())
{
ValueObjectPrinter printer(valobj,&s,DumpValueObjectOptions());
- printer.PrintChildrenOneLiner(HideNames());
+ printer.PrintChildrenOneLiner(HideNames(valobj));
retval.assign(s.GetData());
return true;
}
@@ -95,12 +95,12 @@ StringSummaryFormat::GetDescription ()
sstr.Printf ("`%s`%s%s%s%s%s%s%s", m_format.c_str(),
Cascades() ? "" : " (not cascading)",
- !DoesPrintChildren() ? "" : " (show children)",
- !DoesPrintValue() ? " (hide value)" : "",
+ !DoesPrintChildren(nullptr) ? "" : " (show children)",
+ !DoesPrintValue(nullptr) ? " (hide value)" : "",
IsOneLiner() ? " (one-line printout)" : "",
SkipsPointers() ? " (skip pointers)" : "",
SkipsReferences() ? " (skip references)" : "",
- HideNames() ? " (hide member names)" : "");
+ HideNames(nullptr) ? " (hide member names)" : "");
return sstr.GetString();
}
@@ -129,14 +129,15 @@ std::string
CXXFunctionSummaryFormat::GetDescription ()
{
StreamString sstr;
- sstr.Printf ("`%s (%p) `%s%s%s%s%s%s%s", m_description.c_str(),m_impl,
+ sstr.Printf ("`%s (%p) `%s%s%s%s%s%s%s", m_description.c_str(),
+ static_cast<void*>(&m_impl),
Cascades() ? "" : " (not cascading)",
- !DoesPrintChildren() ? "" : " (show children)",
- !DoesPrintValue() ? " (hide value)" : "",
+ !DoesPrintChildren(nullptr) ? "" : " (show children)",
+ !DoesPrintValue(nullptr) ? " (hide value)" : "",
IsOneLiner() ? " (one-line printout)" : "",
SkipsPointers() ? " (skip pointers)" : "",
SkipsReferences() ? " (skip references)" : "",
- HideNames() ? " (hide member names)" : "");
+ HideNames(nullptr) ? " (hide member names)" : "");
return sstr.GetString();
}
@@ -198,12 +199,12 @@ ScriptSummaryFormat::GetDescription ()
{
StreamString sstr;
sstr.Printf ("%s%s%s%s%s%s%s\n%s", Cascades() ? "" : " (not cascading)",
- !DoesPrintChildren() ? "" : " (show children)",
- !DoesPrintValue() ? " (hide value)" : "",
+ !DoesPrintChildren(nullptr) ? "" : " (show children)",
+ !DoesPrintValue(nullptr) ? " (hide value)" : "",
IsOneLiner() ? " (one-line printout)" : "",
SkipsPointers() ? " (skip pointers)" : "",
SkipsReferences() ? " (skip references)" : "",
- HideNames() ? " (hide member names)" : "",
+ HideNames(nullptr) ? " (hide member names)" : "",
m_python_script.c_str());
return sstr.GetString();
diff --git a/source/DataFormatters/TypeSynthetic.cpp b/source/DataFormatters/TypeSynthetic.cpp
index 972be486b783..3949673a4be8 100644
--- a/source/DataFormatters/TypeSynthetic.cpp
+++ b/source/DataFormatters/TypeSynthetic.cpp
@@ -57,9 +57,9 @@ CXXSyntheticChildren::GetDescription()
Cascades() ? "" : " (not cascading)",
SkipsPointers() ? " (skip pointers)" : "",
SkipsReferences() ? " (skip references)" : "",
- m_create_callback,
+ reinterpret_cast<void*>(reinterpret_cast<intptr_t>(m_create_callback)),
m_description.c_str());
-
+
return sstr.GetString();
}
diff --git a/source/DataFormatters/ValueObjectPrinter.cpp b/source/DataFormatters/ValueObjectPrinter.cpp
index 944d6d2d13a9..65e5e3f45823 100644
--- a/source/DataFormatters/ValueObjectPrinter.cpp
+++ b/source/DataFormatters/ValueObjectPrinter.cpp
@@ -222,7 +222,11 @@ ValueObjectPrinter::PrintTypeIfNeeded ()
{
// Some ValueObjects don't have types (like registers sets). Only print
// the type if there is one to print
- ConstString qualified_type_name(m_valobj->GetQualifiedTypeName());
+ ConstString qualified_type_name;
+ if (options.m_be_raw)
+ qualified_type_name = m_valobj->GetQualifiedTypeName();
+ else
+ qualified_type_name = m_valobj->GetDisplayTypeName();
if (qualified_type_name)
m_stream->Printf("(%s) ", qualified_type_name.GetCString());
else
@@ -341,7 +345,7 @@ ValueObjectPrinter::PrintValueAndSummaryIfNeeded (bool& value_printed,
// the value if this thing is nil
// (but show the value if the user passes a format explicitly)
TypeSummaryImpl* entry = GetSummaryFormatter();
- if (!IsNil() && !m_value.empty() && (entry == NULL || (entry->DoesPrintValue() || options.m_format != eFormatDefault) || m_summary.empty()) && !options.m_hide_value)
+ if (!IsNil() && !m_value.empty() && (entry == NULL || (entry->DoesPrintValue(m_valobj) || options.m_format != eFormatDefault) || m_summary.empty()) && !options.m_hide_value)
{
m_stream->Printf(" %s", m_value.c_str());
value_printed = true;
@@ -426,7 +430,7 @@ ValueObjectPrinter::ShouldPrintChildren (bool is_failed_description,
TypeSummaryImpl* entry = GetSummaryFormatter();
- return (!entry || entry->DoesPrintChildren() || m_summary.empty());
+ return (!entry || entry->DoesPrintChildren(m_valobj) || m_summary.empty());
}
return false;
}
diff --git a/source/Expression/ASTResultSynthesizer.cpp b/source/Expression/ASTResultSynthesizer.cpp
index 76c2577af533..2f14721100bc 100644
--- a/source/Expression/ASTResultSynthesizer.cpp
+++ b/source/Expression/ASTResultSynthesizer.cpp
@@ -40,7 +40,7 @@ ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough,
{
if (!m_passthrough)
return;
-
+
m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
}
@@ -49,10 +49,10 @@ ASTResultSynthesizer::~ASTResultSynthesizer()
}
void
-ASTResultSynthesizer::Initialize(ASTContext &Context)
+ASTResultSynthesizer::Initialize(ASTContext &Context)
{
m_ast_context = &Context;
-
+
if (m_passthrough)
m_passthrough->Initialize(Context);
}
@@ -75,11 +75,11 @@ ASTResultSynthesizer::TransformTopLevelDecl(Decl* D)
}
}
-
+
if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D))
{
RecordDecl::decl_iterator decl_iterator;
-
+
for (decl_iterator = linkage_spec_decl->decls_begin();
decl_iterator != linkage_spec_decl->decls_end();
++decl_iterator)
@@ -107,53 +107,53 @@ ASTResultSynthesizer::TransformTopLevelDecl(Decl* D)
}
}
-bool
+bool
ASTResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D)
{
DeclGroupRef::iterator decl_iterator;
-
+
for (decl_iterator = D.begin();
decl_iterator != D.end();
++decl_iterator)
{
Decl *decl = *decl_iterator;
-
+
TransformTopLevelDecl(decl);
}
-
+
if (m_passthrough)
return m_passthrough->HandleTopLevelDecl(D);
return true;
}
-bool
+bool
ASTResultSynthesizer::SynthesizeFunctionResult (FunctionDecl *FunDecl)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (!m_sema)
return false;
-
+
FunctionDecl *function_decl = FunDecl;
-
+
if (!function_decl)
return false;
-
+
if (log && log->GetVerbose())
{
std::string s;
raw_string_ostream os(s);
-
+
function_decl->print(os);
-
+
os.flush();
-
+
log->Printf ("Untransformed function AST:\n%s", s.c_str());
}
-
+
Stmt *function_body = function_decl->getBody();
CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(function_body);
-
+
bool ret = SynthesizeBodyResult (compound_stmt,
function_decl);
@@ -161,14 +161,14 @@ ASTResultSynthesizer::SynthesizeFunctionResult (FunctionDecl *FunDecl)
{
std::string s;
raw_string_ostream os(s);
-
+
function_decl->print(os);
-
+
os.flush();
-
+
log->Printf ("Transformed function AST:\n%s", s.c_str());
}
-
+
return ret;
}
@@ -176,67 +176,67 @@ bool
ASTResultSynthesizer::SynthesizeObjCMethodResult (ObjCMethodDecl *MethodDecl)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (!m_sema)
return false;
-
+
if (!MethodDecl)
return false;
-
+
if (log && log->GetVerbose())
{
std::string s;
raw_string_ostream os(s);
-
+
MethodDecl->print(os);
-
+
os.flush();
-
+
log->Printf ("Untransformed method AST:\n%s", s.c_str());
}
-
+
Stmt *method_body = MethodDecl->getBody();
-
+
if (!method_body)
return false;
-
+
CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(method_body);
-
+
bool ret = SynthesizeBodyResult (compound_stmt,
MethodDecl);
-
+
if (log && log->GetVerbose())
{
std::string s;
raw_string_ostream os(s);
-
+
MethodDecl->print(os);
-
+
os.flush();
-
+
log->Printf("Transformed method AST:\n%s", s.c_str());
}
-
+
return ret;
}
-bool
-ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body,
+bool
+ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body,
DeclContext *DC)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
ASTContext &Ctx(*m_ast_context);
-
+
if (!Body)
return false;
-
+
if (Body->body_empty())
return false;
-
+
Stmt **last_stmt_ptr = Body->body_end() - 1;
Stmt *last_stmt = *last_stmt_ptr;
-
+
while (dyn_cast<NullStmt>(last_stmt))
{
if (last_stmt_ptr != Body->body_begin())
@@ -249,28 +249,28 @@ ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body,
return false;
}
}
-
+
Expr *last_expr = dyn_cast<Expr>(last_stmt);
-
+
if (!last_expr)
// No auxiliary variable necessary; expression returns void
return true;
-
+
// In C++11, last_expr can be a LValueToRvalue implicit cast. Strip that off if that's the
// case.
-
+
do {
ImplicitCastExpr *implicit_cast = dyn_cast<ImplicitCastExpr>(last_expr);
-
+
if (!implicit_cast)
break;
-
+
if (implicit_cast->getCastKind() != CK_LValueToRValue)
break;
-
+
last_expr = implicit_cast->getSubExpr();
} while (0);
-
+
// is_lvalue is used to record whether the expression returns an assignable Lvalue or an
// Rvalue. This is relevant because they are handled differently.
//
@@ -302,7 +302,7 @@ ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body,
//
// - In IR transformations, an instruction is inserted at the beginning of the function to
// dereference the pointer resident in the slot. Reads and writes to $__lldb_expr_result
- // are redirected at that dereferenced version. Guard variables for the static variable
+ // are redirected at that dereferenced version. Guard variables for the static variable
// are excised.
//
// - During materialization, $0 (the result persistent variable) is populated with the location
@@ -310,46 +310,46 @@ ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body,
//
// - During dematerialization, $0 is ignored.
- bool is_lvalue =
+ bool is_lvalue =
(last_expr->getValueKind() == VK_LValue || last_expr->getValueKind() == VK_XValue) &&
(last_expr->getObjectKind() == OK_Ordinary);
-
+
QualType expr_qual_type = last_expr->getType();
const clang::Type *expr_type = expr_qual_type.getTypePtr();
-
+
if (!expr_type)
return false;
-
+
if (expr_type->isVoidType())
return true;
-
+
if (log)
{
std::string s = expr_qual_type.getAsString();
-
+
log->Printf("Last statement is an %s with type: %s", (is_lvalue ? "lvalue" : "rvalue"), s.c_str());
}
-
+
clang::VarDecl *result_decl = NULL;
-
+
if (is_lvalue)
{
IdentifierInfo *result_ptr_id;
-
+
if (expr_type->isFunctionType())
result_ptr_id = &Ctx.Idents.get("$__lldb_expr_result"); // functions actually should be treated like function pointers
else
result_ptr_id = &Ctx.Idents.get("$__lldb_expr_result_ptr");
-
+
m_sema->RequireCompleteType(SourceLocation(), expr_qual_type, clang::diag::err_incomplete_type);
-
+
QualType ptr_qual_type;
if (expr_qual_type->getAs<ObjCObjectType>() != NULL)
ptr_qual_type = Ctx.getObjCObjectPointerType(expr_qual_type);
else
ptr_qual_type = Ctx.getPointerType(expr_qual_type);
-
+
result_decl = VarDecl::Create(Ctx,
DC,
SourceLocation(),
@@ -358,69 +358,69 @@ ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body,
ptr_qual_type,
NULL,
SC_Static);
-
+
if (!result_decl)
return false;
-
+
ExprResult address_of_expr = m_sema->CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, last_expr);
-
- m_sema->AddInitializerToDecl(result_decl, address_of_expr.take(), true, false);
+
+ m_sema->AddInitializerToDecl(result_decl, address_of_expr.get(), true, false);
}
else
{
IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result");
-
- result_decl = VarDecl::Create(Ctx,
- DC,
+
+ result_decl = VarDecl::Create(Ctx,
+ DC,
SourceLocation(),
SourceLocation(),
- &result_id,
- expr_qual_type,
- NULL,
+ &result_id,
+ expr_qual_type,
+ NULL,
SC_Static);
-
+
if (!result_decl)
return false;
-
+
m_sema->AddInitializerToDecl(result_decl, last_expr, true, false);
}
-
+
DC->addDecl(result_decl);
-
+
///////////////////////////////
// call AddInitializerToDecl
//
-
+
//m_sema->AddInitializerToDecl(result_decl, last_expr);
-
+
/////////////////////////////////
// call ConvertDeclToDeclGroup
//
-
+
Sema::DeclGroupPtrTy result_decl_group_ptr;
-
+
result_decl_group_ptr = m_sema->ConvertDeclToDeclGroup(result_decl);
-
+
////////////////////////
// call ActOnDeclStmt
//
-
+
StmtResult result_initialization_stmt_result(m_sema->ActOnDeclStmt(result_decl_group_ptr,
SourceLocation(),
SourceLocation()));
-
+
////////////////////////////////////////////////
// replace the old statement with the new one
//
-
- *last_stmt_ptr = reinterpret_cast<Stmt*>(result_initialization_stmt_result.take());
+
+ *last_stmt_ptr = reinterpret_cast<Stmt*>(result_initialization_stmt_result.get());
return true;
}
void
ASTResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx)
-{
+{
if (m_passthrough)
m_passthrough->HandleTranslationUnit(Ctx);
}
@@ -429,8 +429,8 @@ void
ASTResultSynthesizer::RecordPersistentTypes(DeclContext *FunDeclCtx)
{
typedef DeclContext::specific_decl_iterator<TypeDecl> TypeDeclIterator;
-
- for (TypeDeclIterator i = TypeDeclIterator(FunDeclCtx->decls_begin()),
+
+ for (TypeDeclIterator i = TypeDeclIterator(FunDeclCtx->decls_begin()),
e = TypeDeclIterator(FunDeclCtx->decls_end());
i != e;
++i)
@@ -439,35 +439,35 @@ ASTResultSynthesizer::RecordPersistentTypes(DeclContext *FunDeclCtx)
}
}
-void
+void
ASTResultSynthesizer::MaybeRecordPersistentType(TypeDecl *D)
{
if (!D->getIdentifier())
return;
-
+
StringRef name = D->getName();
-
+
if (name.size() == 0 || name[0] != '$')
return;
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
ConstString name_cs(name.str().c_str());
-
+
if (log)
log->Printf ("Recording persistent type %s\n", name_cs.GetCString());
-
- Decl *D_scratch = m_target.GetClangASTImporter()->DeportDecl(m_target.GetScratchClangASTContext()->getASTContext(),
+
+ Decl *D_scratch = m_target.GetClangASTImporter()->DeportDecl(m_target.GetScratchClangASTContext()->getASTContext(),
m_ast_context,
D);
-
+
if (TypeDecl *TypeDecl_scratch = dyn_cast<TypeDecl>(D_scratch))
m_target.GetPersistentVariables().RegisterPersistentType(name_cs, TypeDecl_scratch);
}
-void
+void
ASTResultSynthesizer::HandleTagDeclDefinition(TagDecl *D)
-{
+{
if (m_passthrough)
m_passthrough->HandleTagDeclDefinition(D);
}
@@ -479,15 +479,15 @@ ASTResultSynthesizer::CompleteTentativeDefinition(VarDecl *D)
m_passthrough->CompleteTentativeDefinition(D);
}
-void
-ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired)
+void
+ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired)
{
if (m_passthrough)
m_passthrough->HandleVTable(RD, DefinitionRequired);
}
void
-ASTResultSynthesizer::PrintStats()
+ASTResultSynthesizer::PrintStats()
{
if (m_passthrough)
m_passthrough->PrintStats();
@@ -497,16 +497,16 @@ void
ASTResultSynthesizer::InitializeSema(Sema &S)
{
m_sema = &S;
-
+
if (m_passthrough_sema)
m_passthrough_sema->InitializeSema(S);
}
-void
-ASTResultSynthesizer::ForgetSema()
+void
+ASTResultSynthesizer::ForgetSema()
{
m_sema = NULL;
-
+
if (m_passthrough_sema)
m_passthrough_sema->ForgetSema();
}
diff --git a/source/Expression/ASTStructExtractor.cpp b/source/Expression/ASTStructExtractor.cpp
index d1f21923deb4..2a8b7bc7d8ec 100644
--- a/source/Expression/ASTStructExtractor.cpp
+++ b/source/Expression/ASTStructExtractor.cpp
@@ -39,7 +39,7 @@ ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough,
{
if (!m_passthrough)
return;
-
+
m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
}
@@ -48,10 +48,10 @@ ASTStructExtractor::~ASTStructExtractor()
}
void
-ASTStructExtractor::Initialize(ASTContext &Context)
+ASTStructExtractor::Initialize(ASTContext &Context)
{
m_ast_context = &Context;
-
+
if (m_passthrough)
m_passthrough->Initialize(Context);
}
@@ -61,17 +61,17 @@ ASTStructExtractor::ExtractFromFunctionDecl(FunctionDecl *F)
{
if (!F->hasBody())
return;
-
+
Stmt *body_stmt = F->getBody();
CompoundStmt *body_compound_stmt = dyn_cast<CompoundStmt>(body_stmt);
-
+
if (!body_compound_stmt)
return; // do we have to handle this?
-
+
RecordDecl *struct_decl = NULL;
-
+
StringRef desired_name(m_struct_name.c_str());
-
+
for (CompoundStmt::const_body_iterator bi = body_compound_stmt->body_begin(), be = body_compound_stmt->body_end();
bi != be;
++bi)
@@ -95,26 +95,26 @@ ASTStructExtractor::ExtractFromFunctionDecl(FunctionDecl *F)
if (struct_decl)
break;
}
-
+
if (!struct_decl)
return;
-
+
const ASTRecordLayout* struct_layout(&m_ast_context->getASTRecordLayout (struct_decl));
-
+
if (!struct_layout)
return;
-
- m_function.m_struct_size = struct_layout->getSize().getQuantity(); // TODO Store m_struct_size as CharUnits
+
+ m_function.m_struct_size = struct_layout->getSize().getQuantity(); // TODO Store m_struct_size as CharUnits
m_function.m_return_offset = struct_layout->getFieldOffset(struct_layout->getFieldCount() - 1) / 8;
m_function.m_return_size = struct_layout->getDataSize().getQuantity() - m_function.m_return_offset;
-
+
for (unsigned field_index = 0, num_fields = struct_layout->getFieldCount();
field_index < num_fields;
++field_index)
{
m_function.m_member_offsets.push_back(struct_layout->getFieldOffset(field_index) / 8);
}
-
+
m_function.m_struct_valid = true;
}
@@ -122,11 +122,11 @@ void
ASTStructExtractor::ExtractFromTopLevelDecl(Decl* D)
{
LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D);
-
+
if (linkage_spec_decl)
{
RecordDecl::decl_iterator decl_iterator;
-
+
for (decl_iterator = linkage_spec_decl->decls_begin();
decl_iterator != linkage_spec_decl->decls_end();
++decl_iterator)
@@ -134,9 +134,9 @@ ASTStructExtractor::ExtractFromTopLevelDecl(Decl* D)
ExtractFromTopLevelDecl(*decl_iterator);
}
}
-
+
FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D);
-
+
if (m_ast_context &&
function_decl &&
!m_function.m_wrapper_function_name.compare(function_decl->getNameAsString().c_str()))
@@ -145,20 +145,20 @@ ASTStructExtractor::ExtractFromTopLevelDecl(Decl* D)
}
}
-bool
+bool
ASTStructExtractor::HandleTopLevelDecl(DeclGroupRef D)
{
DeclGroupRef::iterator decl_iterator;
-
+
for (decl_iterator = D.begin();
decl_iterator != D.end();
++decl_iterator)
{
Decl *decl = *decl_iterator;
-
+
ExtractFromTopLevelDecl(decl);
}
-
+
if (m_passthrough)
return m_passthrough->HandleTopLevelDecl(D);
return true;
@@ -166,12 +166,12 @@ ASTStructExtractor::HandleTopLevelDecl(DeclGroupRef D)
void
ASTStructExtractor::HandleTranslationUnit(ASTContext &Ctx)
-{
+{
if (m_passthrough)
m_passthrough->HandleTranslationUnit(Ctx);
}
-void
+void
ASTStructExtractor::HandleTagDeclDefinition(TagDecl *D)
{
if (m_passthrough)
@@ -185,15 +185,15 @@ ASTStructExtractor::CompleteTentativeDefinition(VarDecl *D)
m_passthrough->CompleteTentativeDefinition(D);
}
-void
-ASTStructExtractor::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired)
+void
+ASTStructExtractor::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired)
{
if (m_passthrough)
m_passthrough->HandleVTable(RD, DefinitionRequired);
}
void
-ASTStructExtractor::PrintStats()
+ASTStructExtractor::PrintStats()
{
if (m_passthrough)
m_passthrough->PrintStats();
@@ -204,17 +204,17 @@ ASTStructExtractor::InitializeSema(Sema &S)
{
m_sema = &S;
m_action = reinterpret_cast<Action*>(m_sema);
-
+
if (m_passthrough_sema)
m_passthrough_sema->InitializeSema(S);
}
-void
-ASTStructExtractor::ForgetSema()
+void
+ASTStructExtractor::ForgetSema()
{
m_sema = NULL;
m_action = NULL;
-
+
if (m_passthrough_sema)
m_passthrough_sema->ForgetSema();
}
diff --git a/source/Expression/ClangASTSource.cpp b/source/Expression/ClangASTSource.cpp
index 853d102c5426..d488993b90d7 100644
--- a/source/Expression/ClangASTSource.cpp
+++ b/source/Expression/ClangASTSource.cpp
@@ -25,32 +25,32 @@
using namespace clang;
using namespace lldb_private;
-ClangASTSource::~ClangASTSource()
+ClangASTSource::~ClangASTSource()
{
m_ast_importer->ForgetDestination(m_ast_context);
-
+
// We are in the process of destruction, don't create clang ast context on demand
// by passing false to Target::GetScratchClangASTContext(create_on_demand).
ClangASTContext *scratch_clang_ast_context = m_target->GetScratchClangASTContext(false);
-
+
if (!scratch_clang_ast_context)
return;
-
+
clang::ASTContext *scratch_ast_context = scratch_clang_ast_context->getASTContext();
-
+
if (!scratch_ast_context)
return;
-
+
if (m_ast_context != scratch_ast_context)
m_ast_importer->ForgetSource(scratch_ast_context, m_ast_context);
}
void
-ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer)
+ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer)
{
if (!m_ast_context)
return;
-
+
m_ast_context->getTranslationUnitDecl()->setHasExternalVisibleStorage();
m_ast_context->getTranslationUnitDecl()->setHasExternalLexicalStorage();
}
@@ -59,33 +59,33 @@ ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer)
bool
ClangASTSource::FindExternalVisibleDeclsByName
(
- const DeclContext *decl_ctx,
+ const DeclContext *decl_ctx,
DeclarationName clang_decl_name
-)
+)
{
if (!m_ast_context)
{
SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
return false;
}
-
+
if (GetImportInProgress())
{
SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
return false;
}
-
+
std::string decl_name (clang_decl_name.getAsString());
// if (m_decl_map.DoingASTImport ())
// return DeclContext::lookup_result();
-//
+//
switch (clang_decl_name.getNameKind()) {
// Normal identifiers.
case DeclarationName::Identifier:
{
clang::IdentifierInfo *identifier_info = clang_decl_name.getAsIdentifierInfo();
-
+
if (!identifier_info ||
identifier_info->getBuiltinID() != 0)
{
@@ -94,27 +94,27 @@ ClangASTSource::FindExternalVisibleDeclsByName
}
}
break;
-
+
// Operator names. Not important for now.
case DeclarationName::CXXOperatorName:
case DeclarationName::CXXLiteralOperatorName:
SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
return false;
-
+
// Using directives found in this context.
// Tell Sema we didn't find any or we'll end up getting asked a *lot*.
case DeclarationName::CXXUsingDirective:
SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
return false;
-
+
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
{
- llvm::SmallVector<NamedDecl*, 1> method_decls;
+ llvm::SmallVector<NamedDecl*, 1> method_decls;
NameSearchContext method_search_context (*this, method_decls, clang_decl_name, decl_ctx);
-
+
FindObjCMethodDecls(method_search_context);
SetExternalVisibleDeclsForName (decl_ctx, clang_decl_name, method_decls);
@@ -131,21 +131,21 @@ ClangASTSource::FindExternalVisibleDeclsByName
if (!GetLookupsEnabled())
{
- // Wait until we see a '$' at the start of a name before we start doing
+ // Wait until we see a '$' at the start of a name before we start doing
// any lookups so we can avoid lookup up all of the builtin types.
if (!decl_name.empty() && decl_name[0] == '$')
{
SetLookupsEnabled (true);
}
else
- {
+ {
SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
return false;
}
}
ConstString const_decl_name(decl_name.c_str());
-
+
const char *uniqued_const_decl_name = const_decl_name.GetCString();
if (m_active_lookups.find (uniqued_const_decl_name) != m_active_lookups.end())
{
@@ -157,7 +157,7 @@ ClangASTSource::FindExternalVisibleDeclsByName
// static uint32_t g_depth = 0;
// ++g_depth;
// printf("[%5u] FindExternalVisibleDeclsByName() \"%s\"\n", g_depth, uniqued_const_decl_name);
- llvm::SmallVector<NamedDecl*, 4> name_decls;
+ llvm::SmallVector<NamedDecl*, 4> name_decls;
NameSearchContext name_search_context(*this, name_decls, clang_decl_name, decl_ctx);
FindExternalVisibleDecls(name_search_context);
SetExternalVisibleDeclsForName (decl_ctx, clang_decl_name, name_decls);
@@ -168,50 +168,48 @@ ClangASTSource::FindExternalVisibleDeclsByName
void
ClangASTSource::CompleteType (TagDecl *tag_decl)
-{
+{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
static unsigned int invocation_id = 0;
unsigned int current_id = invocation_id++;
-
+
if (log)
{
- log->Printf(" CompleteTagDecl[%u] on (ASTContext*)%p Completing (TagDecl*)%p named %s",
- current_id,
- m_ast_context,
- tag_decl,
+ log->Printf(" CompleteTagDecl[%u] on (ASTContext*)%p Completing (TagDecl*)%p named %s",
+ current_id, static_cast<void*>(m_ast_context),
+ static_cast<void*>(tag_decl),
tag_decl->getName().str().c_str());
-
+
log->Printf(" CTD[%u] Before:", current_id);
ASTDumper dumper((Decl*)tag_decl);
dumper.ToLog(log, " [CTD] ");
}
-
+
if (!m_ast_importer->CompleteTagDecl (tag_decl))
{
// We couldn't complete the type. Maybe there's a definition
// somewhere else that can be completed.
-
+
if (log)
log->Printf(" CTD[%u] Type could not be completed in the module in which it was first found.", current_id);
-
+
bool found = false;
DeclContext *decl_ctx = tag_decl->getDeclContext();
-
+
if (const NamespaceDecl *namespace_context = dyn_cast<NamespaceDecl>(decl_ctx))
{
ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer->GetNamespaceMap(namespace_context);
-
+
if (log && log->GetVerbose())
- log->Printf(" CTD[%u] Inspecting namespace map %p (%d entries)",
- current_id,
- namespace_map.get(),
- (int)namespace_map->size());
-
+ log->Printf(" CTD[%u] Inspecting namespace map %p (%d entries)",
+ current_id, static_cast<void*>(namespace_map.get()),
+ static_cast<int>(namespace_map->size()));
+
if (!namespace_map)
return;
-
+
for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end();
i != e && !found;
++i)
@@ -221,80 +219,80 @@ ClangASTSource::CompleteType (TagDecl *tag_decl)
current_id,
i->second.GetNamespaceDecl()->getNameAsString().c_str(),
i->first->GetFileSpec().GetFilename().GetCString());
-
+
TypeList types;
-
+
SymbolContext null_sc;
ConstString name(tag_decl->getName().str().c_str());
-
+
i->first->FindTypesInNamespace(null_sc, name, &i->second, UINT32_MAX, types);
-
+
for (uint32_t ti = 0, te = types.GetSize();
ti != te && !found;
++ti)
{
lldb::TypeSP type = types.GetTypeAtIndex(ti);
-
+
if (!type)
continue;
-
+
ClangASTType clang_type (type->GetClangFullType());
-
+
if (!clang_type)
continue;
-
+
const TagType *tag_type = clang_type.GetQualType()->getAs<TagType>();
-
+
if (!tag_type)
continue;
-
+
TagDecl *candidate_tag_decl = const_cast<TagDecl*>(tag_type->getDecl());
-
+
if (m_ast_importer->CompleteTagDeclWithOrigin (tag_decl, candidate_tag_decl))
found = true;
}
}
}
- else
+ else
{
TypeList types;
-
+
SymbolContext null_sc;
ConstString name(tag_decl->getName().str().c_str());
ClangNamespaceDecl namespace_decl;
-
+
const ModuleList &module_list = m_target->GetImages();
bool exact_match = false;
module_list.FindTypes (null_sc, name, exact_match, UINT32_MAX, types);
-
+
for (uint32_t ti = 0, te = types.GetSize();
ti != te && !found;
++ti)
{
lldb::TypeSP type = types.GetTypeAtIndex(ti);
-
+
if (!type)
continue;
-
+
ClangASTType clang_type (type->GetClangFullType());
-
+
if (!clang_type)
continue;
-
+
const TagType *tag_type = clang_type.GetQualType()->getAs<TagType>();
-
+
if (!tag_type)
continue;
-
+
TagDecl *candidate_tag_decl = const_cast<TagDecl*>(tag_type->getDecl());
-
+
if (m_ast_importer->CompleteTagDeclWithOrigin (tag_decl, candidate_tag_decl))
found = true;
}
}
}
-
+
if (log)
{
log->Printf(" [CTD] After:");
@@ -305,28 +303,46 @@ ClangASTSource::CompleteType (TagDecl *tag_decl)
void
ClangASTSource::CompleteType (clang::ObjCInterfaceDecl *interface_decl)
-{
+{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (log)
{
- log->Printf(" [CompleteObjCInterfaceDecl] on (ASTContext*)%p Completing an ObjCInterfaceDecl named %s", m_ast_context, interface_decl->getName().str().c_str());
+ log->Printf(" [CompleteObjCInterfaceDecl] on (ASTContext*)%p Completing an ObjCInterfaceDecl named %s",
+ static_cast<void*>(m_ast_context),
+ interface_decl->getName().str().c_str());
log->Printf(" [COID] Before:");
ASTDumper dumper((Decl*)interface_decl);
- dumper.ToLog(log, " [COID] ");
+ dumper.ToLog(log, " [COID] ");
+ }
+
+ Decl *original_decl = NULL;
+ ASTContext *original_ctx = NULL;
+
+ if (m_ast_importer->ResolveDeclOrigin(interface_decl, &original_decl, &original_ctx))
+ {
+ if (ObjCInterfaceDecl *original_iface_decl = dyn_cast<ObjCInterfaceDecl>(original_decl))
+ {
+ ObjCInterfaceDecl *complete_iface_decl = GetCompleteObjCInterface(original_iface_decl);
+
+ if (complete_iface_decl && (complete_iface_decl != original_iface_decl))
+ {
+ m_ast_importer->SetDeclOrigin(interface_decl, original_iface_decl);
+ }
+ }
}
-
+
m_ast_importer->CompleteObjCInterfaceDecl (interface_decl);
-
+
if (interface_decl->getSuperClass() &&
interface_decl->getSuperClass() != interface_decl)
CompleteType(interface_decl->getSuperClass());
-
+
if (log)
{
log->Printf(" [COID] After:");
ASTDumper dumper((Decl*)interface_decl);
- dumper.ToLog(log, " [COID] ");
+ dumper.ToLog(log, " [COID] ");
}
}
@@ -334,36 +350,36 @@ clang::ObjCInterfaceDecl *
ClangASTSource::GetCompleteObjCInterface (clang::ObjCInterfaceDecl *interface_decl)
{
lldb::ProcessSP process(m_target->GetProcessSP());
-
+
if (!process)
return NULL;
-
+
ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
-
+
if (!language_runtime)
return NULL;
-
+
ConstString class_name(interface_decl->getNameAsString().c_str());
-
+
lldb::TypeSP complete_type_sp(language_runtime->LookupInCompleteClassCache(class_name));
-
+
if (!complete_type_sp)
return NULL;
-
+
TypeFromUser complete_type = TypeFromUser(complete_type_sp->GetClangFullType());
lldb::clang_type_t complete_opaque_type = complete_type.GetOpaqueQualType();
-
+
if (!complete_opaque_type)
return NULL;
-
+
const clang::Type *complete_clang_type = QualType::getFromOpaquePtr(complete_opaque_type).getTypePtr();
const ObjCInterfaceType *complete_interface_type = dyn_cast<ObjCInterfaceType>(complete_clang_type);
-
+
if (!complete_interface_type)
return NULL;
-
+
ObjCInterfaceDecl *complete_iface_decl(complete_interface_type->getDecl());
-
+
return complete_iface_decl;
}
@@ -375,83 +391,82 @@ ClangASTSource::FindExternalLexicalDecls (const DeclContext *decl_context,
ClangASTMetrics::RegisterLexicalQuery();
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
const Decl *context_decl = dyn_cast<Decl>(decl_context);
-
+
if (!context_decl)
return ELR_Failure;
-
+
static unsigned int invocation_id = 0;
unsigned int current_id = invocation_id++;
-
+
if (log)
{
if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl))
log->Printf("FindExternalLexicalDecls[%u] on (ASTContext*)%p in '%s' (%sDecl*)%p with %s predicate",
- current_id,
- m_ast_context,
+ current_id, static_cast<void*>(m_ast_context),
context_named_decl->getNameAsString().c_str(),
context_decl->getDeclKindName(),
- context_decl,
+ static_cast<const void*>(context_decl),
(predicate ? "non-null" : "null"));
else if(context_decl)
log->Printf("FindExternalLexicalDecls[%u] on (ASTContext*)%p in (%sDecl*)%p with %s predicate",
- current_id,
- m_ast_context,
- context_decl->getDeclKindName(),
- context_decl,
+ current_id, static_cast<void*>(m_ast_context),
+ context_decl->getDeclKindName(),
+ static_cast<const void*>(context_decl),
(predicate ? "non-null" : "null"));
else
log->Printf("FindExternalLexicalDecls[%u] on (ASTContext*)%p in a NULL context with %s predicate",
- current_id,
- m_ast_context,
+ current_id, static_cast<const void*>(m_ast_context),
(predicate ? "non-null" : "null"));
}
-
+
Decl *original_decl = NULL;
ASTContext *original_ctx = NULL;
-
+
if (!m_ast_importer->ResolveDeclOrigin(context_decl, &original_decl, &original_ctx))
return ELR_Failure;
-
+
if (log)
- {
- log->Printf(" FELD[%u] Original decl (ASTContext*)%p (Decl*)%p:", current_id, original_ctx, original_decl);
+ {
+ log->Printf(" FELD[%u] Original decl (ASTContext*)%p (Decl*)%p:",
+ current_id, static_cast<void*>(original_ctx),
+ static_cast<void*>(original_decl));
ASTDumper(original_decl).ToLog(log, " ");
}
-
+
if (ObjCInterfaceDecl *original_iface_decl = dyn_cast<ObjCInterfaceDecl>(original_decl))
{
ObjCInterfaceDecl *complete_iface_decl = GetCompleteObjCInterface(original_iface_decl);
-
+
if (complete_iface_decl && (complete_iface_decl != original_iface_decl))
{
original_decl = complete_iface_decl;
original_ctx = &complete_iface_decl->getASTContext();
-
+
m_ast_importer->SetDeclOrigin(context_decl, original_iface_decl);
}
}
-
+
if (TagDecl *original_tag_decl = dyn_cast<TagDecl>(original_decl))
{
ExternalASTSource *external_source = original_ctx->getExternalSource();
-
+
if (external_source)
external_source->CompleteType (original_tag_decl);
}
-
+
const DeclContext *original_decl_context = dyn_cast<DeclContext>(original_decl);
-
+
if (!original_decl_context)
return ELR_Failure;
-
+
for (TagDecl::decl_iterator iter = original_decl_context->decls_begin();
iter != original_decl_context->decls_end();
++iter)
{
Decl *decl = *iter;
-
+
if (!predicate || predicate(decl->getKind()))
{
if (log)
@@ -462,35 +477,35 @@ ClangASTSource::FindExternalLexicalDecls (const DeclContext *decl_context,
else
log->Printf(" FELD[%d] Adding lexical %sDecl %s", current_id, decl->getDeclKindName(), ast_dumper.GetCString());
}
-
+
Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, original_ctx, decl);
-
+
if (!copied_decl)
continue;
-
+
if (FieldDecl *copied_field = dyn_cast<FieldDecl>(copied_decl))
{
QualType copied_field_type = copied_field->getType();
-
+
m_ast_importer->RequireCompleteType(copied_field_type);
}
-
+
decls.push_back(copied_decl);
-
+
DeclContext *decl_context_non_const = const_cast<DeclContext *>(decl_context);
-
+
if (copied_decl->getDeclContext() != decl_context)
{
if (copied_decl->getDeclContext()->containsDecl(copied_decl))
copied_decl->getDeclContext()->removeDecl(copied_decl);
copied_decl->setDeclContext(decl_context_non_const);
}
-
+
if (!decl_context_non_const->containsDecl(copied_decl))
decl_context_non_const->addDeclInternal(copied_decl);
}
}
-
+
return ELR_AlreadyLoaded;
}
@@ -498,41 +513,48 @@ void
ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context)
{
assert (m_ast_context);
-
+
ClangASTMetrics::RegisterVisibleQuery();
-
+
const ConstString name(context.m_decl_name.getAsString().c_str());
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
static unsigned int invocation_id = 0;
unsigned int current_id = invocation_id++;
-
+
if (log)
{
if (!context.m_decl_context)
- log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in a NULL DeclContext", current_id, m_ast_context, name.GetCString());
+ log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in a NULL DeclContext",
+ current_id, static_cast<void*>(m_ast_context),
+ name.GetCString());
else if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context.m_decl_context))
- log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in '%s'", current_id, m_ast_context, name.GetCString(), context_named_decl->getNameAsString().c_str());
+ log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in '%s'",
+ current_id, static_cast<void*>(m_ast_context),
+ name.GetCString(),
+ context_named_decl->getNameAsString().c_str());
else
- log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in a '%s'", current_id, m_ast_context, name.GetCString(), context.m_decl_context->getDeclKindName());
+ log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in a '%s'",
+ current_id, static_cast<void*>(m_ast_context),
+ name.GetCString(),
+ context.m_decl_context->getDeclKindName());
}
-
+
context.m_namespace_map.reset(new ClangASTImporter::NamespaceMap);
-
+
if (const NamespaceDecl *namespace_context = dyn_cast<NamespaceDecl>(context.m_decl_context))
{
ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer->GetNamespaceMap(namespace_context);
-
+
if (log && log->GetVerbose())
- log->Printf(" CAS::FEVD[%u] Inspecting namespace map %p (%d entries)",
- current_id,
- namespace_map.get(),
- (int)namespace_map->size());
-
+ log->Printf(" CAS::FEVD[%u] Inspecting namespace map %p (%d entries)",
+ current_id, static_cast<void*>(namespace_map.get()),
+ static_cast<int>(namespace_map->size()));
+
if (!namespace_map)
return;
-
+
for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end();
i != e;
++i)
@@ -542,7 +564,7 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context)
current_id,
i->second.GetNamespaceDecl()->getNameAsString().c_str(),
i->first->GetFileSpec().GetFilename().GetCString());
-
+
FindExternalVisibleDecls(context,
i->first,
i->second,
@@ -561,158 +583,158 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context)
else
{
ClangNamespaceDecl namespace_decl;
-
+
if (log)
log->Printf(" CAS::FEVD[%u] Searching the root namespace", current_id);
-
+
FindExternalVisibleDecls(context,
lldb::ModuleSP(),
namespace_decl,
current_id);
}
-
+
if (!context.m_namespace_map->empty())
{
if (log && log->GetVerbose())
- log->Printf(" CAS::FEVD[%u] Registering namespace map %p (%d entries)",
+ log->Printf(" CAS::FEVD[%u] Registering namespace map %p (%d entries)",
current_id,
- context.m_namespace_map.get(),
- (int)context.m_namespace_map->size());
-
+ static_cast<void*>(context.m_namespace_map.get()),
+ static_cast<int>(context.m_namespace_map->size()));
+
NamespaceDecl *clang_namespace_decl = AddNamespace(context, context.m_namespace_map);
-
+
if (clang_namespace_decl)
clang_namespace_decl->setHasExternalVisibleStorage();
}
}
-void
-ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
+void
+ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
lldb::ModuleSP module_sp,
ClangNamespaceDecl &namespace_decl,
unsigned int current_id)
{
assert (m_ast_context);
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
SymbolContextList sc_list;
-
+
const ConstString name(context.m_decl_name.getAsString().c_str());
-
+
const char *name_unique_cstr = name.GetCString();
-
+
static ConstString id_name("id");
static ConstString Class_name("Class");
-
+
if (name == id_name || name == Class_name)
return;
-
+
if (name_unique_cstr == NULL)
return;
-
+
// The ClangASTSource is not responsible for finding $-names.
if (name_unique_cstr[0] == '$')
return;
-
+
if (module_sp && namespace_decl)
{
ClangNamespaceDecl found_namespace_decl;
-
+
SymbolVendor *symbol_vendor = module_sp->GetSymbolVendor();
-
+
if (symbol_vendor)
{
SymbolContext null_sc;
-
+
found_namespace_decl = symbol_vendor->FindNamespace(null_sc, name, &namespace_decl);
-
+
if (found_namespace_decl)
{
context.m_namespace_map->push_back(std::pair<lldb::ModuleSP, ClangNamespaceDecl>(module_sp, found_namespace_decl));
-
+
if (log)
log->Printf(" CAS::FEVD[%u] Found namespace %s in module %s",
current_id,
- name.GetCString(),
+ name.GetCString(),
module_sp->GetFileSpec().GetFilename().GetCString());
}
}
}
- else
+ else
{
const ModuleList &target_images = m_target->GetImages();
Mutex::Locker modules_locker (target_images.GetMutex());
-
+
for (size_t i = 0, e = target_images.GetSize(); i < e; ++i)
{
lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i);
-
+
if (!image)
continue;
-
+
ClangNamespaceDecl found_namespace_decl;
-
+
SymbolVendor *symbol_vendor = image->GetSymbolVendor();
-
+
if (!symbol_vendor)
continue;
-
+
SymbolContext null_sc;
-
+
found_namespace_decl = symbol_vendor->FindNamespace(null_sc, name, &namespace_decl);
-
+
if (found_namespace_decl)
{
context.m_namespace_map->push_back(std::pair<lldb::ModuleSP, ClangNamespaceDecl>(image, found_namespace_decl));
-
+
if (log)
log->Printf(" CAS::FEVD[%u] Found namespace %s in module %s",
current_id,
- name.GetCString(),
+ name.GetCString(),
image->GetFileSpec().GetFilename().GetCString());
}
}
}
-
- do
+
+ do
{
TypeList types;
SymbolContext null_sc;
const bool exact_match = false;
-
+
if (module_sp && namespace_decl)
module_sp->FindTypesInNamespace(null_sc, name, &namespace_decl, 1, types);
- else
+ else
m_target->GetImages().FindTypes(null_sc, name, exact_match, 1, types);
-
+
if (types.GetSize())
{
lldb::TypeSP type_sp = types.GetTypeAtIndex(0);
-
+
if (log)
{
const char *name_string = type_sp->GetName().GetCString();
-
- log->Printf(" CAS::FEVD[%u] Matching type found for \"%s\": %s",
- current_id,
- name.GetCString(),
+
+ log->Printf(" CAS::FEVD[%u] Matching type found for \"%s\": %s",
+ current_id,
+ name.GetCString(),
(name_string ? name_string : "<anonymous>"));
}
-
+
ClangASTType full_type = type_sp->GetClangFullType();
ClangASTType copied_clang_type (GuardedCopyType(full_type));
-
+
if (!copied_clang_type)
- {
+ {
if (log)
log->Printf(" CAS::FEVD[%u] - Couldn't export a type",
current_id);
-
+
break;
}
-
+
context.AddTypeDecl(copied_clang_type);
}
else
@@ -720,55 +742,55 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
do
{
// Couldn't find any types elsewhere. Try the Objective-C runtime if one exists.
-
+
lldb::ProcessSP process(m_target->GetProcessSP());
-
+
if (!process)
break;
-
+
ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
-
+
if (!language_runtime)
break;
-
+
TypeVendor *type_vendor = language_runtime->GetTypeVendor();
-
+
if (!type_vendor)
break;
-
+
bool append = false;
uint32_t max_matches = 1;
std::vector <ClangASTType> types;
-
+
if (!type_vendor->FindTypes(name,
append,
max_matches,
types))
break;
-
+
if (log)
- {
+ {
log->Printf(" CAS::FEVD[%u] Matching type found for \"%s\" in the runtime",
current_id,
name.GetCString());
}
-
+
ClangASTType copied_clang_type (GuardedCopyType(types[0]));
-
+
if (!copied_clang_type)
{
if (log)
log->Printf(" CAS::FEVD[%u] - Couldn't export a type from the runtime",
current_id);
-
+
break;
}
-
+
context.AddTypeDecl(copied_clang_type);
}
while(0);
}
-
+
} while(0);
}
@@ -782,7 +804,7 @@ public:
D *decl;
};
-template <class D2, template <class D> class TD, class D1>
+template <class D2, template <class D> class TD, class D1>
TD<D2>
DynCast(TD<D1> source)
{
@@ -792,19 +814,19 @@ DynCast(TD<D1> source)
template <class D = Decl> class DeclFromParser;
template <class D = Decl> class DeclFromUser;
-template <class D> class DeclFromParser : public TaggedASTDecl<D> {
+template <class D> class DeclFromParser : public TaggedASTDecl<D> {
public:
DeclFromParser() : TaggedASTDecl<D>() { }
DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) { }
-
+
DeclFromUser<D> GetOrigin(ClangASTImporter *importer);
};
-template <class D> class DeclFromUser : public TaggedASTDecl<D> {
+template <class D> class DeclFromUser : public TaggedASTDecl<D> {
public:
DeclFromUser() : TaggedASTDecl<D>() { }
DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) { }
-
+
DeclFromParser<D> Import(ClangASTImporter *importer, ASTContext &dest_ctx);
};
@@ -841,7 +863,7 @@ FindObjCMethodDeclsWithOrigin (unsigned int current_id,
clang::ASTContext *original_ctx = &original_interface_decl->getASTContext();
Selector original_selector;
-
+
if (decl_name.isObjCZeroArgSelector())
{
IdentifierInfo *ident = &original_ctx->Idents.get(decl_name.getAsString());
@@ -857,59 +879,59 @@ FindObjCMethodDeclsWithOrigin (unsigned int current_id,
else
{
SmallVector<IdentifierInfo *, 4> idents;
-
+
clang::Selector sel = decl_name.getObjCSelector();
-
+
unsigned num_args = sel.getNumArgs();
-
+
for (unsigned i = 0;
i != num_args;
++i)
{
idents.push_back(&original_ctx->Idents.get(sel.getNameForSlot(i)));
}
-
+
original_selector = original_ctx->Selectors.getSelector(num_args, idents.data());
}
-
+
DeclarationName original_decl_name(original_selector);
-
+
ObjCInterfaceDecl::lookup_result result = original_interface_decl->lookup(original_decl_name);
-
+
if (result.empty())
return false;
-
+
if (!result[0])
return false;
-
+
for (NamedDecl *named_decl : result)
{
ObjCMethodDecl *result_method = dyn_cast<ObjCMethodDecl>(named_decl);
-
+
if (!result_method)
return false;
-
+
Decl *copied_decl = ast_importer->CopyDecl(ast_context, &result_method->getASTContext(), result_method);
-
+
if (!copied_decl)
return false;
-
+
ObjCMethodDecl *copied_method_decl = dyn_cast<ObjCMethodDecl>(copied_decl);
-
+
if (!copied_method_decl)
return false;
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (log)
{
ASTDumper dumper((Decl*)copied_method_decl);
log->Printf(" CAS::FOMD[%d] found (%s) %s", current_id, log_info, dumper.GetCString());
}
-
+
context.AddNamedDecl(copied_method_decl);
}
-
+
return true;
}
@@ -917,30 +939,30 @@ void
ClangASTSource::FindObjCMethodDecls (NameSearchContext &context)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
static unsigned int invocation_id = 0;
unsigned int current_id = invocation_id++;
-
+
const DeclarationName &decl_name(context.m_decl_name);
const DeclContext *decl_ctx(context.m_decl_context);
-
+
const ObjCInterfaceDecl *interface_decl = dyn_cast<ObjCInterfaceDecl>(decl_ctx);
-
+
if (!interface_decl)
return;
-
+
do
{
Decl *original_decl = NULL;
ASTContext *original_ctx = NULL;
-
+
m_ast_importer->ResolveDeclOrigin(interface_decl, &original_decl, &original_ctx);
-
+
if (!original_decl)
break;
-
+
ObjCInterfaceDecl *original_interface_decl = dyn_cast<ObjCInterfaceDecl>(original_decl);
-
+
if (FindObjCMethodDeclsWithOrigin(current_id,
context,
original_interface_decl,
@@ -949,9 +971,9 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context)
"at origin"))
return; // found it, no need to look any further
} while (0);
-
+
StreamString ss;
-
+
if (decl_name.isObjCZeroArgSelector())
{
ss.Printf("%s", decl_name.getAsString().c_str());
@@ -961,234 +983,232 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context)
ss.Printf("%s", decl_name.getAsString().c_str());
}
else
- {
+ {
clang::Selector sel = decl_name.getObjCSelector();
-
+
for (unsigned i = 0, e = sel.getNumArgs();
i != e;
++i)
{
llvm::StringRef r = sel.getNameForSlot(i);
- ss.Printf("%s:", r.str().c_str());
+ ss.Printf("%s:", r.str().c_str());
}
- }
+ }
ss.Flush();
-
+
if (strstr(ss.GetData(), "$__lldb"))
return; // we don't need any results
-
+
ConstString selector_name(ss.GetData());
-
+
if (log)
log->Printf("ClangASTSource::FindObjCMethodDecls[%d] on (ASTContext*)%p for selector [%s %s]",
- current_id,
- m_ast_context,
- interface_decl->getNameAsString().c_str(),
+ current_id, static_cast<void*>(m_ast_context),
+ interface_decl->getNameAsString().c_str(),
selector_name.AsCString());
SymbolContextList sc_list;
-
+
const bool include_symbols = false;
const bool include_inlines = false;
const bool append = false;
-
+
std::string interface_name = interface_decl->getNameAsString();
-
+
do
{
StreamString ms;
ms.Printf("-[%s %s]", interface_name.c_str(), selector_name.AsCString());
ms.Flush();
ConstString instance_method_name(ms.GetData());
-
+
m_target->GetImages().FindFunctions(instance_method_name, lldb::eFunctionNameTypeFull, include_symbols, include_inlines, append, sc_list);
-
+
if (sc_list.GetSize())
break;
-
+
ms.Clear();
ms.Printf("+[%s %s]", interface_name.c_str(), selector_name.AsCString());
ms.Flush();
ConstString class_method_name(ms.GetData());
-
+
m_target->GetImages().FindFunctions(class_method_name, lldb::eFunctionNameTypeFull, include_symbols, include_inlines, append, sc_list);
-
+
if (sc_list.GetSize())
break;
-
+
// Fall back and check for methods in categories. If we find methods this way, we need to check that they're actually in
// categories on the desired class.
-
+
SymbolContextList candidate_sc_list;
-
+
m_target->GetImages().FindFunctions(selector_name, lldb::eFunctionNameTypeSelector, include_symbols, include_inlines, append, candidate_sc_list);
-
+
for (uint32_t ci = 0, ce = candidate_sc_list.GetSize();
ci != ce;
++ci)
{
SymbolContext candidate_sc;
-
+
if (!candidate_sc_list.GetContextAtIndex(ci, candidate_sc))
continue;
-
+
if (!candidate_sc.function)
continue;
-
+
const char *candidate_name = candidate_sc.function->GetName().AsCString();
-
+
const char *cursor = candidate_name;
-
+
if (*cursor != '+' && *cursor != '-')
continue;
-
+
++cursor;
-
+
if (*cursor != '[')
continue;
-
+
++cursor;
-
+
size_t interface_len = interface_name.length();
-
+
if (strncmp(cursor, interface_name.c_str(), interface_len))
continue;
-
+
cursor += interface_len;
-
+
if (*cursor == ' ' || *cursor == '(')
sc_list.Append(candidate_sc);
}
}
while (0);
-
+
if (sc_list.GetSize())
{
// We found a good function symbol. Use that.
-
+
for (uint32_t i = 0, e = sc_list.GetSize();
i != e;
++i)
{
SymbolContext sc;
-
+
if (!sc_list.GetContextAtIndex(i, sc))
continue;
-
+
if (!sc.function)
continue;
-
+
DeclContext *function_ctx = sc.function->GetClangDeclContext();
-
+
if (!function_ctx)
continue;
-
+
ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(function_ctx);
-
+
if (!method_decl)
continue;
-
+
ObjCInterfaceDecl *found_interface_decl = method_decl->getClassInterface();
-
+
if (!found_interface_decl)
continue;
-
+
if (found_interface_decl->getName() == interface_decl->getName())
{
Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, &method_decl->getASTContext(), method_decl);
-
+
if (!copied_decl)
continue;
-
+
ObjCMethodDecl *copied_method_decl = dyn_cast<ObjCMethodDecl>(copied_decl);
-
+
if (!copied_method_decl)
continue;
-
+
if (log)
{
ASTDumper dumper((Decl*)copied_method_decl);
log->Printf(" CAS::FOMD[%d] found (in symbols) %s", current_id, dumper.GetCString());
}
-
+
context.AddNamedDecl(copied_method_decl);
}
}
-
+
return;
}
-
+
// Try the debug information.
-
+
do
{
ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast<ObjCInterfaceDecl*>(interface_decl));
-
+
if (!complete_interface_decl)
break;
-
+
// We found the complete interface. The runtime never needs to be queried in this scenario.
-
+
DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(complete_interface_decl);
-
+
if (complete_interface_decl == interface_decl)
break; // already checked this one
-
+
if (log)
log->Printf("CAS::FOPD[%d] trying origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
- current_id,
- complete_interface_decl,
- &complete_iface_decl->getASTContext());
-
+ current_id, static_cast<void*>(complete_interface_decl),
+ static_cast<void*>(&complete_iface_decl->getASTContext()));
+
FindObjCMethodDeclsWithOrigin(current_id,
context,
complete_interface_decl,
m_ast_context,
m_ast_importer,
"in debug info");
-
+
return;
}
while (0);
-
+
do
{
// Check the runtime only if the debug information didn't have a complete interface.
-
+
lldb::ProcessSP process(m_target->GetProcessSP());
-
+
if (!process)
break;
-
+
ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
-
+
if (!language_runtime)
break;
-
+
TypeVendor *type_vendor = language_runtime->GetTypeVendor();
-
+
if (!type_vendor)
break;
-
+
ConstString interface_name(interface_decl->getNameAsString().c_str());
bool append = false;
uint32_t max_matches = 1;
std::vector <ClangASTType> types;
-
+
if (!type_vendor->FindTypes(interface_name,
append,
max_matches,
types))
break;
-
+
const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr();
-
+
const ObjCInterfaceType *runtime_interface_type = dyn_cast<ObjCInterfaceType>(runtime_clang_type);
-
+
if (!runtime_interface_type)
break;
-
+
ObjCInterfaceDecl *runtime_interface_decl = runtime_interface_type->getDecl();
-
+
FindObjCMethodDeclsWithOrigin(current_id,
context,
runtime_interface_decl,
@@ -1200,7 +1220,7 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context)
}
static bool
-FindObjCPropertyAndIvarDeclsWithOrigin (unsigned int current_id,
+FindObjCPropertyAndIvarDeclsWithOrigin (unsigned int current_id,
NameSearchContext &context,
clang::ASTContext &ast_context,
ClangASTImporter *ast_importer,
@@ -1210,15 +1230,15 @@ FindObjCPropertyAndIvarDeclsWithOrigin (unsigned int current_id,
if (origin_iface_decl.IsInvalid())
return false;
-
+
std::string name_str = context.m_decl_name.getAsString();
StringRef name(name_str.c_str());
IdentifierInfo &name_identifier(origin_iface_decl->getASTContext().Idents.get(name));
-
+
DeclFromUser<ObjCPropertyDecl> origin_property_decl(origin_iface_decl->FindPropertyDeclaration(&name_identifier));
-
+
bool found = false;
-
+
if (origin_property_decl.IsValid())
{
DeclFromParser<ObjCPropertyDecl> parser_property_decl(origin_property_decl.Import(ast_importer, ast_context));
@@ -1229,14 +1249,14 @@ FindObjCPropertyAndIvarDeclsWithOrigin (unsigned int current_id,
ASTDumper dumper((Decl*)parser_property_decl.decl);
log->Printf(" CAS::FOPD[%d] found %s", current_id, dumper.GetCString());
}
-
+
context.AddNamedDecl(parser_property_decl.decl);
found = true;
}
}
-
+
DeclFromUser<ObjCIvarDecl> origin_ivar_decl(origin_iface_decl->getIvarDecl(&name_identifier));
-
+
if (origin_ivar_decl.IsValid())
{
DeclFromParser<ObjCIvarDecl> parser_ivar_decl(origin_ivar_decl.Import(ast_importer, ast_context));
@@ -1247,12 +1267,12 @@ FindObjCPropertyAndIvarDeclsWithOrigin (unsigned int current_id,
ASTDumper dumper((Decl*)parser_ivar_decl.decl);
log->Printf(" CAS::FOPD[%d] found %s", current_id, dumper.GetCString());
}
-
+
context.AddNamedDecl(parser_ivar_decl.decl);
found = true;
}
}
-
+
return found;
}
@@ -1263,109 +1283,107 @@ ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context)
static unsigned int invocation_id = 0;
unsigned int current_id = invocation_id++;
-
+
DeclFromParser<const ObjCInterfaceDecl> parser_iface_decl(cast<ObjCInterfaceDecl>(context.m_decl_context));
DeclFromUser<const ObjCInterfaceDecl> origin_iface_decl(parser_iface_decl.GetOrigin(m_ast_importer));
ConstString class_name(parser_iface_decl->getNameAsString().c_str());
-
+
if (log)
log->Printf("ClangASTSource::FindObjCPropertyAndIvarDecls[%d] on (ASTContext*)%p for '%s.%s'",
- current_id,
- m_ast_context,
- parser_iface_decl->getNameAsString().c_str(),
+ current_id, static_cast<void*>(m_ast_context),
+ parser_iface_decl->getNameAsString().c_str(),
context.m_decl_name.getAsString().c_str());
-
- if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
- context,
- *m_ast_context,
- m_ast_importer,
+
+ if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
+ context,
+ *m_ast_context,
+ m_ast_importer,
origin_iface_decl))
return;
-
+
if (log)
log->Printf("CAS::FOPD[%d] couldn't find the property on origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p, searching elsewhere...",
- current_id,
- origin_iface_decl.decl,
- &origin_iface_decl->getASTContext());
-
+ current_id, static_cast<const void*>(origin_iface_decl.decl),
+ static_cast<void*>(&origin_iface_decl->getASTContext()));
+
SymbolContext null_sc;
TypeList type_list;
-
+
do
{
ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast<ObjCInterfaceDecl*>(parser_iface_decl.decl));
-
+
if (!complete_interface_decl)
break;
-
+
// We found the complete interface. The runtime never needs to be queried in this scenario.
-
+
DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(complete_interface_decl);
-
+
if (complete_iface_decl.decl == origin_iface_decl.decl)
break; // already checked this one
-
+
if (log)
log->Printf("CAS::FOPD[%d] trying origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
current_id,
- complete_iface_decl.decl,
- &complete_iface_decl->getASTContext());
-
- FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
- context,
- *m_ast_context,
- m_ast_importer,
+ static_cast<const void*>(complete_iface_decl.decl),
+ static_cast<void*>(&complete_iface_decl->getASTContext()));
+
+ FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
+ context,
+ *m_ast_context,
+ m_ast_importer,
complete_iface_decl);
-
+
return;
}
while(0);
-
+
do
{
// Check the runtime only if the debug information didn't have a complete interface.
-
+
lldb::ProcessSP process(m_target->GetProcessSP());
-
+
if (!process)
return;
-
+
ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
-
+
if (!language_runtime)
return;
-
+
TypeVendor *type_vendor = language_runtime->GetTypeVendor();
-
+
if (!type_vendor)
break;
-
+
bool append = false;
uint32_t max_matches = 1;
std::vector <ClangASTType> types;
-
+
if (!type_vendor->FindTypes(class_name,
append,
max_matches,
types))
break;
-
+
const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr();
const ObjCInterfaceType *runtime_interface_type = dyn_cast<ObjCInterfaceType>(runtime_clang_type);
-
+
if (!runtime_interface_type)
break;
-
+
DeclFromUser<const ObjCInterfaceDecl> runtime_iface_decl(runtime_interface_type->getDecl());
-
+
if (log)
log->Printf("CAS::FOPD[%d] trying runtime (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
current_id,
- runtime_iface_decl.decl,
- &runtime_iface_decl->getASTContext());
-
+ static_cast<const void*>(runtime_iface_decl.decl),
+ static_cast<void*>(&runtime_iface_decl->getASTContext()));
+
if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
context,
*m_ast_context,
@@ -1381,13 +1399,13 @@ typedef llvm::DenseMap <const CXXRecordDecl *, CharUnits> BaseOffsetMap;
template <class D, class O>
static bool
-ImportOffsetMap (llvm::DenseMap <const D*, O> &destination_map,
+ImportOffsetMap (llvm::DenseMap <const D*, O> &destination_map,
llvm::DenseMap <const D*, O> &source_map,
ClangASTImporter *importer,
ASTContext &dest_ctx)
{
typedef llvm::DenseMap <const D*, O> MapType;
-
+
for (typename MapType::iterator fi = source_map.begin(), fe = source_map.end();
fi != fe;
++fi)
@@ -1398,7 +1416,7 @@ ImportOffsetMap (llvm::DenseMap <const D*, O> &destination_map,
return false;
destination_map.insert(std::pair<const D *, O>(parser_decl.decl, fi->second));
}
-
+
return true;
}
@@ -1406,102 +1424,98 @@ template <bool IsVirtual> bool ExtractBaseOffsets (const ASTRecordLayout &record
DeclFromUser<const CXXRecordDecl> &record,
BaseOffsetMap &base_offsets)
{
- for (CXXRecordDecl::base_class_const_iterator
- bi = (IsVirtual ? record->vbases_begin() : record->bases_begin()),
+ for (CXXRecordDecl::base_class_const_iterator
+ bi = (IsVirtual ? record->vbases_begin() : record->bases_begin()),
be = (IsVirtual ? record->vbases_end() : record->bases_end());
bi != be;
++bi)
{
if (!IsVirtual && bi->isVirtual())
continue;
-
+
const clang::Type *origin_base_type = bi->getType().getTypePtr();
const clang::RecordType *origin_base_record_type = origin_base_type->getAs<RecordType>();
-
+
if (!origin_base_record_type)
return false;
-
+
DeclFromUser <RecordDecl> origin_base_record(origin_base_record_type->getDecl());
-
+
if (origin_base_record.IsInvalid())
return false;
-
+
DeclFromUser <CXXRecordDecl> origin_base_cxx_record(DynCast<CXXRecordDecl>(origin_base_record));
-
+
if (origin_base_cxx_record.IsInvalid())
return false;
-
+
CharUnits base_offset;
-
+
if (IsVirtual)
base_offset = record_layout.getVBaseClassOffset(origin_base_cxx_record.decl);
else
base_offset = record_layout.getBaseClassOffset(origin_base_cxx_record.decl);
-
+
base_offsets.insert(std::pair<const CXXRecordDecl *, CharUnits>(origin_base_cxx_record.decl, base_offset));
}
-
+
return true;
}
-
-bool
+
+bool
ClangASTSource::layoutRecordType(const RecordDecl *record,
- uint64_t &size,
+ uint64_t &size,
uint64_t &alignment,
FieldOffsetMap &field_offsets,
BaseOffsetMap &base_offsets,
BaseOffsetMap &virtual_base_offsets)
{
ClangASTMetrics::RegisterRecordLayout();
-
+
static unsigned int invocation_id = 0;
unsigned int current_id = invocation_id++;
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (log)
- {
log->Printf("LayoutRecordType[%u] on (ASTContext*)%p for (RecordDecl*)%p [name = '%s']",
- current_id,
- m_ast_context,
- record,
+ current_id, static_cast<void*>(m_ast_context),
+ static_cast<const void*>(record),
record->getNameAsString().c_str());
- }
-
-
+
DeclFromParser <const RecordDecl> parser_record(record);
DeclFromUser <const RecordDecl> origin_record(parser_record.GetOrigin(m_ast_importer));
-
+
if (origin_record.IsInvalid())
return false;
-
+
FieldOffsetMap origin_field_offsets;
BaseOffsetMap origin_base_offsets;
BaseOffsetMap origin_virtual_base_offsets;
-
+
ClangASTContext::GetCompleteDecl(&origin_record->getASTContext(), const_cast<RecordDecl*>(origin_record.decl));
-
+
if (!origin_record.decl->getDefinition())
return false;
-
+
const ASTRecordLayout &record_layout(origin_record->getASTContext().getASTRecordLayout(origin_record.decl));
-
+
int field_idx = 0, field_count = record_layout.getFieldCount();
-
+
for (RecordDecl::field_iterator fi = origin_record->field_begin(), fe = origin_record->field_end();
fi != fe;
++fi)
{
if (field_idx >= field_count)
return false; // Layout didn't go well. Bail out.
-
+
uint64_t field_offset = record_layout.getFieldOffset(field_idx);
-
+
origin_field_offsets.insert(std::pair<const FieldDecl *, uint64_t>(*fi, field_offset));
-
+
field_idx++;
}
-
+
ASTContext &parser_ast_context(record->getASTContext());
DeclFromUser <const CXXRecordDecl> origin_cxx_record(DynCast<const CXXRecordDecl>(origin_record));
@@ -1517,14 +1531,15 @@ ClangASTSource::layoutRecordType(const RecordDecl *record,
!ImportOffsetMap(base_offsets, origin_base_offsets, m_ast_importer, parser_ast_context) ||
!ImportOffsetMap(virtual_base_offsets, origin_virtual_base_offsets, m_ast_importer, parser_ast_context))
return false;
-
+
size = record_layout.getSize().getQuantity() * m_ast_context->getCharWidth();
alignment = record_layout.getAlignment().getQuantity() * m_ast_context->getCharWidth();
-
+
if (log)
{
log->Printf("LRT[%u] returned:", current_id);
- log->Printf("LRT[%u] Original = (RecordDecl*)%p", current_id, origin_record.decl);
+ log->Printf("LRT[%u] Original = (RecordDecl*)%p", current_id,
+ static_cast<const void*>(origin_record.decl));
log->Printf("LRT[%u] Size = %" PRId64, current_id, size);
log->Printf("LRT[%u] Alignment = %" PRId64, current_id, alignment);
log->Printf("LRT[%u] Fields:", current_id);
@@ -1533,10 +1548,8 @@ ClangASTSource::layoutRecordType(const RecordDecl *record,
++fi)
{
log->Printf("LRT[%u] (FieldDecl*)%p, Name = '%s', Offset = %" PRId64 " bits",
- current_id,
- *fi,
- fi->getNameAsString().c_str(),
- field_offsets[*fi]);
+ current_id, static_cast<void*>(*fi),
+ fi->getNameAsString().c_str(), field_offsets[*fi]);
}
DeclFromParser <const CXXRecordDecl> parser_cxx_record = DynCast<const CXXRecordDecl>(parser_record);
if (parser_cxx_record.IsValid())
@@ -1547,19 +1560,19 @@ ClangASTSource::layoutRecordType(const RecordDecl *record,
++bi)
{
bool is_virtual = bi->isVirtual();
-
+
QualType base_type = bi->getType();
const RecordType *base_record_type = base_type->getAs<RecordType>();
DeclFromParser <RecordDecl> base_record(base_record_type->getDecl());
DeclFromParser <CXXRecordDecl> base_cxx_record = DynCast<CXXRecordDecl>(base_record);
-
+
log->Printf("LRT[%u] %s(CXXRecordDecl*)%p, Name = '%s', Offset = %" PRId64 " chars",
- current_id,
- (is_virtual ? "Virtual " : ""),
- base_cxx_record.decl,
+ current_id, (is_virtual ? "Virtual " : ""),
+ static_cast<void*>(base_cxx_record.decl),
base_cxx_record.decl->getNameAsString().c_str(),
- (is_virtual ? virtual_base_offsets[base_cxx_record.decl].getQuantity() :
- base_offsets[base_cxx_record.decl].getQuantity()));
+ (is_virtual
+ ? virtual_base_offsets[base_cxx_record.decl].getQuantity()
+ : base_offsets[base_cxx_record.decl].getQuantity()));
}
}
else
@@ -1567,36 +1580,33 @@ ClangASTSource::layoutRecordType(const RecordDecl *record,
log->Printf("LRD[%u] Not a CXXRecord, so no bases", current_id);
}
}
-
+
return true;
}
-void
+void
ClangASTSource::CompleteNamespaceMap (ClangASTImporter::NamespaceMapSP &namespace_map,
const ConstString &name,
ClangASTImporter::NamespaceMapSP &parent_map) const
{
static unsigned int invocation_id = 0;
unsigned int current_id = invocation_id++;
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (log)
{
if (parent_map && parent_map->size())
log->Printf("CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for namespace %s in namespace %s",
- current_id,
- m_ast_context,
+ current_id, static_cast<void*>(m_ast_context),
name.GetCString(),
parent_map->begin()->second.GetNamespaceDecl()->getDeclName().getAsString().c_str());
else
log->Printf("CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for namespace %s",
- current_id,
- m_ast_context,
+ current_id, static_cast<void*>(m_ast_context),
name.GetCString());
}
-
-
+
if (parent_map)
{
for (ClangASTImporter::NamespaceMap::iterator i = parent_map->begin(), e = parent_map->end();
@@ -1604,28 +1614,28 @@ ClangASTSource::CompleteNamespaceMap (ClangASTImporter::NamespaceMapSP &namespac
++i)
{
ClangNamespaceDecl found_namespace_decl;
-
+
lldb::ModuleSP module_sp = i->first;
ClangNamespaceDecl module_parent_namespace_decl = i->second;
-
+
SymbolVendor *symbol_vendor = module_sp->GetSymbolVendor();
-
+
if (!symbol_vendor)
continue;
-
+
SymbolContext null_sc;
-
+
found_namespace_decl = symbol_vendor->FindNamespace(null_sc, name, &module_parent_namespace_decl);
-
+
if (!found_namespace_decl)
continue;
-
+
namespace_map->push_back(std::pair<lldb::ModuleSP, ClangNamespaceDecl>(module_sp, found_namespace_decl));
-
+
if (log)
log->Printf(" CMN[%u] Found namespace %s in module %s",
current_id,
- name.GetCString(),
+ name.GetCString(),
module_sp->GetFileSpec().GetFilename().GetCString());
}
}
@@ -1633,36 +1643,36 @@ ClangASTSource::CompleteNamespaceMap (ClangASTImporter::NamespaceMapSP &namespac
{
const ModuleList &target_images = m_target->GetImages();
Mutex::Locker modules_locker(target_images.GetMutex());
-
+
ClangNamespaceDecl null_namespace_decl;
-
+
for (size_t i = 0, e = target_images.GetSize(); i < e; ++i)
{
lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i);
-
+
if (!image)
continue;
-
+
ClangNamespaceDecl found_namespace_decl;
-
+
SymbolVendor *symbol_vendor = image->GetSymbolVendor();
-
+
if (!symbol_vendor)
continue;
-
+
SymbolContext null_sc;
-
+
found_namespace_decl = symbol_vendor->FindNamespace(null_sc, name, &null_namespace_decl);
-
+
if (!found_namespace_decl)
continue;
-
+
namespace_map->push_back(std::pair<lldb::ModuleSP, ClangNamespaceDecl>(image, found_namespace_decl));
-
+
if (log)
log->Printf(" CMN[%u] Found namespace %s in module %s",
current_id,
- name.GetCString(),
+ name.GetCString(),
image->GetFileSpec().GetFilename().GetCString());
}
}
@@ -1673,23 +1683,23 @@ ClangASTSource::AddNamespace (NameSearchContext &context, ClangASTImporter::Name
{
if (!namespace_decls)
return NULL;
-
+
const ClangNamespaceDecl &namespace_decl = namespace_decls->begin()->second;
-
+
Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, namespace_decl.GetASTContext(), namespace_decl.GetNamespaceDecl());
-
+
if (!copied_decl)
return NULL;
-
+
NamespaceDecl *copied_namespace_decl = dyn_cast<NamespaceDecl>(copied_decl);
-
+
if (!copied_namespace_decl)
return NULL;
-
+
context.m_decls.push_back(copied_namespace_decl);
-
+
m_ast_importer->RegisterNamespaceMap(copied_namespace_decl, namespace_decls);
-
+
return dyn_cast<NamespaceDecl>(copied_decl);
}
@@ -1697,18 +1707,18 @@ ClangASTType
ClangASTSource::GuardedCopyType (const ClangASTType &src_type)
{
ClangASTMetrics::RegisterLLDBImport();
-
+
SetImportInProgress(true);
-
+
QualType copied_qual_type = m_ast_importer->CopyType (m_ast_context, src_type.GetASTContext(), src_type.GetQualType());
-
+
SetImportInProgress(false);
-
+
if (copied_qual_type.getAsOpaquePtr() && copied_qual_type->getCanonicalTypeInternal().isNull())
// this shouldn't happen, but we're hardening because the AST importer seems to be generating bad types
// on occasion.
return ClangASTType();
-
+
return ClangASTType(m_ast_context, copied_qual_type);
}
@@ -1719,39 +1729,39 @@ NameSearchContext::AddVarDecl(const ClangASTType &type)
if (!type.IsValid())
return NULL;
-
+
IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo();
-
+
clang::ASTContext *ast = type.GetASTContext();
clang::NamedDecl *Decl = VarDecl::Create(*ast,
- const_cast<DeclContext*>(m_decl_context),
- SourceLocation(),
+ const_cast<DeclContext*>(m_decl_context),
+ SourceLocation(),
SourceLocation(),
- ii,
+ ii,
type.GetQualType(),
- 0,
+ 0,
SC_Static);
m_decls.push_back(Decl);
-
+
return Decl;
}
clang::NamedDecl *
-NameSearchContext::AddFunDecl (const ClangASTType &type)
+NameSearchContext::AddFunDecl (const ClangASTType &type)
{
assert (type && "Type for variable must be valid!");
-
+
if (!type.IsValid())
return NULL;
if (m_function_types.count(type))
return NULL;
-
+
m_function_types.insert(type);
-
+
QualType qual_type (type.GetQualType());
-
+
clang::ASTContext *ast = type.GetASTContext();
const bool isInlineSpecified = false;
@@ -1773,20 +1783,20 @@ NameSearchContext::AddFunDecl (const ClangASTType &type)
// We have to do more than just synthesize the FunctionDecl. We have to
// synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do
// this, we raid the function's FunctionProtoType for types.
-
+
const FunctionProtoType *func_proto_type = qual_type.getTypePtr()->getAs<FunctionProtoType>();
-
+
if (func_proto_type)
- {
+ {
unsigned NumArgs = func_proto_type->getNumParams();
unsigned ArgIndex;
-
+
SmallVector<ParmVarDecl *, 5> parm_var_decls;
-
+
for (ArgIndex = 0; ArgIndex < NumArgs; ++ArgIndex)
{
QualType arg_qual_type (func_proto_type->getParamType(ArgIndex));
-
+
parm_var_decls.push_back(ParmVarDecl::Create (*ast,
const_cast<DeclContext*>(m_decl_context),
SourceLocation(),
@@ -1797,7 +1807,7 @@ NameSearchContext::AddFunDecl (const ClangASTType &type)
SC_Static,
NULL));
}
-
+
func_decl->setParams(ArrayRef<ParmVarDecl*>(parm_var_decls));
}
else
@@ -1807,9 +1817,9 @@ NameSearchContext::AddFunDecl (const ClangASTType &type)
if (log)
log->Printf("Function type wasn't a FunctionProtoType");
}
-
+
m_decls.push_back(func_decl);
-
+
return func_decl;
}
@@ -1817,13 +1827,13 @@ clang::NamedDecl *
NameSearchContext::AddGenericFunDecl()
{
FunctionProtoType::ExtProtoInfo proto_info;
-
+
proto_info.Variadic = true;
-
+
QualType generic_function_type(m_ast_source.m_ast_context->getFunctionType (m_ast_source.m_ast_context->UnknownAnyTy, // result
ArrayRef<QualType>(), // argument types
proto_info));
-
+
return AddFunDecl(ClangASTType (m_ast_source.m_ast_context, generic_function_type));
}
@@ -1837,32 +1847,32 @@ NameSearchContext::AddTypeDecl(const ClangASTType &clang_type)
if (const TypedefType *typedef_type = llvm::dyn_cast<TypedefType>(qual_type))
{
TypedefNameDecl *typedef_name_decl = typedef_type->getDecl();
-
+
m_decls.push_back(typedef_name_decl);
-
+
return (NamedDecl*)typedef_name_decl;
}
else if (const TagType *tag_type = qual_type->getAs<TagType>())
{
TagDecl *tag_decl = tag_type->getDecl();
-
+
m_decls.push_back(tag_decl);
-
+
return tag_decl;
}
else if (const ObjCObjectType *objc_object_type = qual_type->getAs<ObjCObjectType>())
{
ObjCInterfaceDecl *interface_decl = objc_object_type->getInterface();
-
+
m_decls.push_back((NamedDecl*)interface_decl);
-
+
return (NamedDecl*)interface_decl;
}
}
return NULL;
}
-void
+void
NameSearchContext::AddLookupResult (clang::DeclContextLookupConstResult result)
{
for (clang::NamedDecl *decl : result)
diff --git a/source/Expression/ClangExpressionDeclMap.cpp b/source/Expression/ClangExpressionDeclMap.cpp
index 198fde93386e..43c8a5fb1bcb 100644
--- a/source/Expression/ClangExpressionDeclMap.cpp
+++ b/source/Expression/ClangExpressionDeclMap.cpp
@@ -8,11 +8,6 @@
//===----------------------------------------------------------------------===//
#include "lldb/Expression/ClangExpressionDeclMap.h"
-
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Decl.h"
@@ -68,21 +63,21 @@ ClangExpressionDeclMap::~ClangExpressionDeclMap()
{
// Note: The model is now that the parser's AST context and all associated
// data does not vanish until the expression has been executed. This means
- // that valuable lookup data (like namespaces) doesn't vanish, but
-
+ // that valuable lookup data (like namespaces) doesn't vanish, but
+
DidParse();
DisableStructVars();
}
-bool
+bool
ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx,
Materializer *materializer)
{
ClangASTMetrics::ClearLocalCounters();
-
+
EnableParserVars();
m_parser_vars->m_exe_ctx = exe_ctx;
-
+
Target *target = exe_ctx.GetTargetPtr();
if (exe_ctx.GetFramePtr())
m_parser_vars->m_sym_ctx = exe_ctx.GetFramePtr()->GetSymbolContext(lldb::eSymbolContextEverything);
@@ -98,18 +93,18 @@ ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx,
m_parser_vars->m_sym_ctx.Clear(true);
m_parser_vars->m_sym_ctx.target_sp = exe_ctx.GetTargetSP();
}
-
+
if (target)
{
m_parser_vars->m_persistent_vars = &target->GetPersistentVariables();
-
+
if (!target->GetScratchClangASTContext())
return false;
}
-
+
m_parser_vars->m_target_info = GetTargetInfo();
m_parser_vars->m_materializer = materializer;
-
+
return true;
}
@@ -120,7 +115,7 @@ ClangExpressionDeclMap::DidParse()
if (log)
ClangASTMetrics::DumpCounters(log);
-
+
if (m_parser_vars.get())
{
for (size_t entity_index = 0, num_entities = m_found_entities.GetSize();
@@ -131,7 +126,7 @@ ClangExpressionDeclMap::DidParse()
if (var_sp)
var_sp->DisableParserVars(GetParserID());
}
-
+
for (size_t pvar_index = 0, num_pvars = m_parser_vars->m_persistent_vars->GetSize();
pvar_index < num_pvars;
++pvar_index)
@@ -140,20 +135,20 @@ ClangExpressionDeclMap::DidParse()
if (pvar_sp)
pvar_sp->DisableParserVars(GetParserID());
}
-
+
DisableParserVars();
}
}
// Interface for IRForTarget
-ClangExpressionDeclMap::TargetInfo
+ClangExpressionDeclMap::TargetInfo
ClangExpressionDeclMap::GetTargetInfo()
{
assert (m_parser_vars.get());
-
+
TargetInfo ret;
-
+
ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
Process *process = exe_ctx.GetProcessPtr();
@@ -162,7 +157,7 @@ ClangExpressionDeclMap::GetTargetInfo()
ret.byte_order = process->GetByteOrder();
ret.address_byte_size = process->GetAddressByteSize();
}
- else
+ else
{
Target *target = exe_ctx.GetTargetPtr();
if (target)
@@ -175,61 +170,61 @@ ClangExpressionDeclMap::GetTargetInfo()
return ret;
}
-bool
-ClangExpressionDeclMap::AddPersistentVariable
+bool
+ClangExpressionDeclMap::AddPersistentVariable
(
- const NamedDecl *decl,
- const ConstString &name,
+ const NamedDecl *decl,
+ const ConstString &name,
TypeFromParser parser_type,
bool is_result,
bool is_lvalue
)
{
assert (m_parser_vars.get());
-
+
if (m_parser_vars->m_materializer && is_result)
{
Error err;
-
+
ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
Target *target = exe_ctx.GetTargetPtr();
if (target == NULL)
return false;
-
+
ASTContext *context(target->GetScratchClangASTContext()->getASTContext());
-
+
TypeFromUser user_type(m_ast_importer->DeportType(context,
parser_type.GetASTContext(),
parser_type.GetOpaqueQualType()),
context);
-
+
uint32_t offset = m_parser_vars->m_materializer->AddResultVariable(user_type, is_lvalue, m_keep_result_in_memory, err);
-
+
ClangExpressionVariableSP var_sp = m_found_entities.CreateVariable(exe_ctx.GetBestExecutionContextScope(),
name,
user_type,
m_parser_vars->m_target_info.byte_order,
m_parser_vars->m_target_info.address_byte_size);
-
+
if (!var_sp)
return false;
-
+
var_sp->EnableParserVars(GetParserID());
-
+
ClangExpressionVariable::ParserVars *parser_vars = var_sp->GetParserVars(GetParserID());
parser_vars->m_named_decl = decl;
parser_vars->m_parser_type = parser_type;
-
+
var_sp->EnableJITVars(GetParserID());
-
+
ClangExpressionVariable::JITVars *jit_vars = var_sp->GetJITVars(GetParserID());
-
+
jit_vars->m_offset = offset;
-
+
return true;
}
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
Target *target = exe_ctx.GetTargetPtr();
@@ -237,38 +232,38 @@ ClangExpressionDeclMap::AddPersistentVariable
return false;
ASTContext *context(target->GetScratchClangASTContext()->getASTContext());
-
- TypeFromUser user_type(m_ast_importer->DeportType(context,
+
+ TypeFromUser user_type(m_ast_importer->DeportType(context,
parser_type.GetASTContext(),
parser_type.GetOpaqueQualType()),
context);
-
+
if (!user_type.GetOpaqueQualType())
{
if (log)
log->Printf("Persistent variable's type wasn't copied successfully");
return false;
}
-
+
if (!m_parser_vars->m_target_info.IsValid())
return false;
-
+
ClangExpressionVariableSP var_sp = m_parser_vars->m_persistent_vars->CreatePersistentVariable (exe_ctx.GetBestExecutionContextScope (),
name,
user_type,
m_parser_vars->m_target_info.byte_order,
m_parser_vars->m_target_info.address_byte_size);
-
+
if (!var_sp)
return false;
-
+
var_sp->m_frozen_sp->SetHasCompleteType();
-
+
if (is_result)
var_sp->m_flags |= ClangExpressionVariable::EVNeedsFreezeDry;
else
var_sp->m_flags |= ClangExpressionVariable::EVKeepInTarget; // explicitly-declared persistent variables should persist
-
+
if (is_lvalue)
{
var_sp->m_flags |= ClangExpressionVariable::EVIsProgramReference;
@@ -278,88 +273,87 @@ ClangExpressionDeclMap::AddPersistentVariable
var_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
var_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
}
-
+
if (m_keep_result_in_memory)
{
var_sp->m_flags |= ClangExpressionVariable::EVKeepInTarget;
}
-
+
if (log)
log->Printf("Created persistent variable with flags 0x%hx", var_sp->m_flags);
-
+
var_sp->EnableParserVars(GetParserID());
-
+
ClangExpressionVariable::ParserVars *parser_vars = var_sp->GetParserVars(GetParserID());
-
+
parser_vars->m_named_decl = decl;
parser_vars->m_parser_type = parser_type;
-
+
return true;
}
-bool
-ClangExpressionDeclMap::AddValueToStruct
+bool
+ClangExpressionDeclMap::AddValueToStruct
(
const NamedDecl *decl,
const ConstString &name,
llvm::Value *value,
size_t size,
- off_t alignment
+ lldb::offset_t alignment
)
{
assert (m_struct_vars.get());
assert (m_parser_vars.get());
-
+
bool is_persistent_variable = false;
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
m_struct_vars->m_struct_laid_out = false;
-
+
if (m_struct_members.GetVariable(decl, GetParserID()))
return true;
-
+
ClangExpressionVariableSP var_sp (m_found_entities.GetVariable(decl, GetParserID()));
-
+
if (!var_sp)
{
var_sp = m_parser_vars->m_persistent_vars->GetVariable(decl, GetParserID());
is_persistent_variable = true;
}
-
+
if (!var_sp)
return false;
-
+
if (log)
log->Printf("Adding value for (NamedDecl*)%p [%s - %s] to the structure",
- decl,
- name.GetCString(),
+ static_cast<const void*>(decl), name.GetCString(),
var_sp->GetName().GetCString());
-
+
// We know entity->m_parser_vars is valid because we used a parser variable
// to find it
-
+
ClangExpressionVariable::ParserVars *parser_vars = var_sp->GetParserVars(GetParserID());
parser_vars->m_llvm_value = value;
-
+
if (ClangExpressionVariable::JITVars *jit_vars = var_sp->GetJITVars(GetParserID()))
{
// We already laid this out; do not touch
-
+
if (log)
log->Printf("Already placed at 0x%llx", (unsigned long long)jit_vars->m_offset);
}
-
+
var_sp->EnableJITVars(GetParserID());
-
+
ClangExpressionVariable::JITVars *jit_vars = var_sp->GetJITVars(GetParserID());
jit_vars->m_alignment = alignment;
jit_vars->m_size = size;
-
+
m_struct_members.AddVariable(var_sp);
-
+
if (m_parser_vars->m_materializer)
{
uint32_t offset = 0;
@@ -379,16 +373,16 @@ ClangExpressionDeclMap::AddValueToStruct
else if (parser_vars->m_lldb_var)
offset = m_parser_vars->m_materializer->AddVariable(parser_vars->m_lldb_var, err);
}
-
+
if (!err.Success())
return false;
-
+
if (log)
log->Printf("Placed at 0x%llx", (unsigned long long)offset);
-
+
jit_vars->m_offset = offset; // TODO DoStructLayout() should not change this.
}
-
+
return true;
}
@@ -396,81 +390,81 @@ bool
ClangExpressionDeclMap::DoStructLayout ()
{
assert (m_struct_vars.get());
-
+
if (m_struct_vars->m_struct_laid_out)
return true;
-
+
if (!m_parser_vars->m_materializer)
return false;
-
+
m_struct_vars->m_struct_alignment = m_parser_vars->m_materializer->GetStructAlignment();
m_struct_vars->m_struct_size = m_parser_vars->m_materializer->GetStructByteSize();
m_struct_vars->m_struct_laid_out = true;
return true;
}
-bool ClangExpressionDeclMap::GetStructInfo
+bool ClangExpressionDeclMap::GetStructInfo
(
uint32_t &num_elements,
size_t &size,
- off_t &alignment
+ lldb::offset_t &alignment
)
{
assert (m_struct_vars.get());
-
+
if (!m_struct_vars->m_struct_laid_out)
return false;
-
+
num_elements = m_struct_members.GetSize();
size = m_struct_vars->m_struct_size;
alignment = m_struct_vars->m_struct_alignment;
-
+
return true;
}
-bool
-ClangExpressionDeclMap::GetStructElement
+bool
+ClangExpressionDeclMap::GetStructElement
(
const NamedDecl *&decl,
llvm::Value *&value,
- off_t &offset,
+ lldb::offset_t &offset,
ConstString &name,
uint32_t index
)
{
assert (m_struct_vars.get());
-
+
if (!m_struct_vars->m_struct_laid_out)
return false;
-
+
if (index >= m_struct_members.GetSize())
return false;
-
+
ClangExpressionVariableSP member_sp(m_struct_members.GetVariableAtIndex(index));
-
+
if (!member_sp)
return false;
-
+
ClangExpressionVariable::ParserVars *parser_vars = member_sp->GetParserVars(GetParserID());
ClangExpressionVariable::JITVars *jit_vars = member_sp->GetJITVars(GetParserID());
-
+
if (!parser_vars ||
!jit_vars ||
!member_sp->GetValueObject())
return false;
-
+
decl = parser_vars->m_named_decl;
value = parser_vars->m_llvm_value;
offset = jit_vars->m_offset;
name = member_sp->GetName();
-
+
return true;
}
bool
-ClangExpressionDeclMap::GetFunctionInfo
+ClangExpressionDeclMap::GetFunctionInfo
(
- const NamedDecl *decl,
+ const NamedDecl *decl,
uint64_t &ptr
)
{
@@ -478,14 +472,14 @@ ClangExpressionDeclMap::GetFunctionInfo
if (!entity_sp)
return false;
-
+
// We know m_parser_vars is valid since we searched for the variable by
// its NamedDecl
-
+
ClangExpressionVariable::ParserVars *parser_vars = entity_sp->GetParserVars(GetParserID());
ptr = parser_vars->m_lldb_value.GetScalar().ULongLong();
-
+
return true;
}
@@ -500,7 +494,7 @@ FindCodeSymbolInContext
SymbolContextList temp_sc_list;
if (sym_ctx.module_sp)
sym_ctx.module_sp->FindSymbolsWithNameAndType(name, eSymbolTypeAny, temp_sc_list);
-
+
if (!sc_list.GetSize() && sym_ctx.target_sp)
sym_ctx.target_sp->GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeAny, temp_sc_list);
@@ -527,14 +521,14 @@ FindCodeSymbolInContext
}
bool
-ClangExpressionDeclMap::GetFunctionAddress
+ClangExpressionDeclMap::GetFunctionAddress
(
const ConstString &name,
uint64_t &func_addr
)
{
assert (m_parser_vars.get());
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
Target *target = exe_ctx.GetTargetPtr();
@@ -545,25 +539,25 @@ ClangExpressionDeclMap::GetFunctionAddress
return false;
SymbolContextList sc_list;
-
+
FindCodeSymbolInContext(name, m_parser_vars->m_sym_ctx, sc_list);
uint32_t sc_list_size = sc_list.GetSize();
if (sc_list_size == 0)
{
- // We occasionally get debug information in which a const function is reported
+ // We occasionally get debug information in which a const function is reported
// as non-const, so the mangled name is wrong. This is a hack to compensate.
-
+
if (!strncmp(name.GetCString(), "_ZN", 3) &&
strncmp(name.GetCString(), "_ZNK", 4))
{
std::string fixed_scratch("_ZNK");
fixed_scratch.append(name.GetCString() + 3);
ConstString fixed_name(fixed_scratch.c_str());
-
+
if (log)
log->Printf("Failed to find symbols given non-const name %s; trying %s", name.GetCString(), fixed_name.GetCString());
-
+
FindCodeSymbolInContext(fixed_name, m_parser_vars->m_sym_ctx, sc_list);
sc_list_size = sc_list.GetSize();
}
@@ -574,37 +568,25 @@ ClangExpressionDeclMap::GetFunctionAddress
SymbolContext sym_ctx;
sc_list.GetContextAtIndex(i, sym_ctx);
- const Address *func_so_addr = NULL;
- bool is_indirect_function = false;
+ lldb::addr_t callable_load_addr = LLDB_INVALID_ADDRESS;
+
if (sym_ctx.function)
- func_so_addr = &sym_ctx.function->GetAddressRange().GetBaseAddress();
- else if (sym_ctx.symbol)
{
- if (sym_ctx.symbol->GetType() == eSymbolTypeReExported)
- {
- Symbol *reexported_symbol = sym_ctx.symbol->ResolveReExportedSymbol(*target);
- if (reexported_symbol)
- {
- func_so_addr = &reexported_symbol->GetAddress();
- is_indirect_function = reexported_symbol->IsIndirect();
- }
- }
- else
+ const Address func_so_addr = sym_ctx.function->GetAddressRange().GetBaseAddress();
+ if (func_so_addr.IsValid())
{
- func_so_addr = &sym_ctx.symbol->GetAddress();
- is_indirect_function = sym_ctx.symbol->IsIndirect();
+ callable_load_addr = func_so_addr.GetCallableLoadAddress(target, false);
}
}
+ else if (sym_ctx.symbol)
+ {
+ callable_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target);
+ }
- if (func_so_addr && func_so_addr->IsValid())
+ if (callable_load_addr != LLDB_INVALID_ADDRESS)
{
- lldb::addr_t load_addr = func_so_addr->GetCallableLoadAddress (target, is_indirect_function);
-
- if (load_addr != LLDB_INVALID_ADDRESS)
- {
- func_addr = load_addr;
- return true;
- }
+ func_addr = callable_load_addr;
+ return true;
}
}
return false;
@@ -618,12 +600,12 @@ ClangExpressionDeclMap::GetSymbolAddress (Target &target,
lldb_private::Module *module)
{
SymbolContextList sc_list;
-
+
if (module)
module->FindSymbolsWithNameAndType(name, symbol_type, sc_list);
else
target.GetImages().FindSymbolsWithNameAndType(name, symbol_type, sc_list);
-
+
const uint32_t num_matches = sc_list.GetSize();
addr_t symbol_load_addr = LLDB_INVALID_ADDRESS;
@@ -631,12 +613,12 @@ ClangExpressionDeclMap::GetSymbolAddress (Target &target,
{
SymbolContext sym_ctx;
sc_list.GetContextAtIndex(i, sym_ctx);
-
+
const Address *sym_address = &sym_ctx.symbol->GetAddress();
-
+
if (!sym_address || !sym_address->IsValid())
continue;
-
+
if (sym_address)
{
switch (sym_ctx.symbol->GetType())
@@ -702,17 +684,17 @@ ClangExpressionDeclMap::GetSymbolAddress (Target &target,
}
}
}
-
+
if (symbol_load_addr == LLDB_INVALID_ADDRESS && process)
{
ObjCLanguageRuntime *runtime = process->GetObjCLanguageRuntime();
-
+
if (runtime)
{
symbol_load_addr = runtime->LookupRuntimeSymbol(name);
}
}
-
+
return symbol_load_addr;
}
@@ -720,10 +702,10 @@ addr_t
ClangExpressionDeclMap::GetSymbolAddress (const ConstString &name, lldb::SymbolType symbol_type)
{
assert (m_parser_vars.get());
-
+
if (!m_parser_vars->m_exe_ctx.GetTargetPtr())
return false;
-
+
return GetSymbolAddress(m_parser_vars->m_exe_ctx.GetTargetRef(), m_parser_vars->m_exe_ctx.GetProcessPtr(), name, symbol_type);
}
@@ -733,12 +715,12 @@ ClangExpressionDeclMap::FindGlobalDataSymbol (Target &target,
lldb_private::Module *module)
{
SymbolContextList sc_list;
-
+
if (module)
module->FindSymbolsWithNameAndType(name, eSymbolTypeAny, sc_list);
else
target.GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeAny, sc_list);
-
+
const uint32_t matches = sc_list.GetSize();
for (uint32_t i=0; i<matches; ++i)
{
@@ -748,7 +730,7 @@ ClangExpressionDeclMap::FindGlobalDataSymbol (Target &target,
{
const Symbol *symbol = sym_ctx.symbol;
const Address *sym_address = &symbol->GetAddress();
-
+
if (sym_address && sym_address->IsValid())
{
switch (symbol->GetType())
@@ -790,7 +772,7 @@ ClangExpressionDeclMap::FindGlobalDataSymbol (Target &target,
}
}
break;
-
+
case eSymbolTypeCode: // We already lookup functions elsewhere
case eSymbolTypeVariable:
case eSymbolTypeLocal:
@@ -818,7 +800,7 @@ ClangExpressionDeclMap::FindGlobalDataSymbol (Target &target,
}
}
}
-
+
return NULL;
}
@@ -833,12 +815,12 @@ ClangExpressionDeclMap::FindGlobalVariable
)
{
VariableList vars;
-
+
if (module && namespace_decl)
module->FindGlobalVariables (name, namespace_decl, true, -1, vars);
else
target.GetImages().FindGlobalVariables(name, true, -1, vars);
-
+
if (vars.GetSize())
{
if (type)
@@ -846,7 +828,7 @@ ClangExpressionDeclMap::FindGlobalVariable
for (size_t i = 0; i < vars.GetSize(); ++i)
{
VariableSP var_sp = vars.GetVariableAtIndex(i);
-
+
if (ClangASTContext::AreTypesSame(*type, var_sp->GetType()->GetClangFullType()))
return var_sp;
}
@@ -856,7 +838,7 @@ ClangExpressionDeclMap::FindGlobalVariable
return vars.GetVariableAtIndex(0);
}
}
-
+
return VariableSP();
}
@@ -866,23 +848,23 @@ void
ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context)
{
assert (m_ast_context);
-
+
ClangASTMetrics::RegisterVisibleQuery();
-
+
const ConstString name(context.m_decl_name.getAsString().c_str());
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (GetImportInProgress())
{
if (log && log->GetVerbose())
log->Printf("Ignoring a query during an import");
return;
}
-
+
static unsigned int invocation_id = 0;
unsigned int current_id = invocation_id++;
-
+
if (log)
{
if (!context.m_decl_context)
@@ -892,20 +874,19 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context)
else
log->Printf("ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for '%s' in a '%s'", current_id, name.GetCString(), context.m_decl_context->getDeclKindName());
}
-
+
if (const NamespaceDecl *namespace_context = dyn_cast<NamespaceDecl>(context.m_decl_context))
{
ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer->GetNamespaceMap(namespace_context);
-
+
if (log && log->GetVerbose())
- log->Printf(" CEDM::FEVD[%u] Inspecting (NamespaceMap*)%p (%d entries)",
- current_id,
- namespace_map.get(),
+ log->Printf(" CEDM::FEVD[%u] Inspecting (NamespaceMap*)%p (%d entries)",
+ current_id, static_cast<void*>(namespace_map.get()),
(int)namespace_map->size());
-
+
if (!namespace_map)
return;
-
+
for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end();
i != e;
++i)
@@ -915,7 +896,7 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context)
current_id,
i->second.GetNamespaceDecl()->getNameAsString().c_str(),
i->first->GetFileSpec().GetFilename().GetCString());
-
+
FindExternalVisibleDecls(context,
i->first,
i->second,
@@ -925,65 +906,65 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context)
else if (isa<TranslationUnitDecl>(context.m_decl_context))
{
ClangNamespaceDecl namespace_decl;
-
+
if (log)
log->Printf(" CEDM::FEVD[%u] Searching the root namespace", current_id);
-
+
FindExternalVisibleDecls(context,
lldb::ModuleSP(),
namespace_decl,
current_id);
}
-
+
if (!context.m_found.variable)
ClangASTSource::FindExternalVisibleDecls(context);
}
-void
-ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
+void
+ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
lldb::ModuleSP module_sp,
ClangNamespaceDecl &namespace_decl,
unsigned int current_id)
{
assert (m_ast_context);
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
SymbolContextList sc_list;
-
+
const ConstString name(context.m_decl_name.getAsString().c_str());
-
+
const char *name_unique_cstr = name.GetCString();
-
+
if (name_unique_cstr == NULL)
return;
-
+
static ConstString id_name("id");
static ConstString Class_name("Class");
-
+
if (name == id_name || name == Class_name)
return;
-
- // Only look for functions by name out in our symbols if the function
+
+ // Only look for functions by name out in our symbols if the function
// doesn't start with our phony prefix of '$'
Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr();
if (name_unique_cstr[0] == '$' && !namespace_decl)
{
static ConstString g_lldb_class_name ("$__lldb_class");
-
+
if (name == g_lldb_class_name)
{
// Clang is looking for the type of "this"
-
+
if (frame == NULL)
return;
-
+
SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction);
-
+
if (!sym_ctx.function)
return;
-
+
// Get the block that defines the function
Block *function_block = sym_ctx.GetFunctionBlock();
@@ -991,59 +972,59 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
return;
clang::DeclContext *decl_context = function_block->GetClangDeclContext();
-
+
if (!decl_context)
return;
-
+
clang::CXXMethodDecl *method_decl = llvm::dyn_cast<clang::CXXMethodDecl>(decl_context);
-
+
if (method_decl)
{
clang::CXXRecordDecl *class_decl = method_decl->getParent();
-
+
QualType class_qual_type(class_decl->getTypeForDecl(), 0);
-
+
TypeFromUser class_user_type (class_qual_type.getAsOpaquePtr(),
&class_decl->getASTContext());
-
+
if (log)
{
ASTDumper ast_dumper(class_qual_type);
log->Printf(" CEDM::FEVD[%u] Adding type for $__lldb_class: %s", current_id, ast_dumper.GetCString());
}
-
+
TypeFromParser class_type = CopyClassType(class_user_type, current_id);
-
+
if (!class_type.IsValid())
return;
-
+
TypeSourceInfo *type_source_info = m_ast_context->getTrivialTypeSourceInfo(QualType::getFromOpaquePtr(class_type.GetOpaqueQualType()));
-
+
if (!type_source_info)
return;
-
+
TypedefDecl *typedef_decl = TypedefDecl::Create(*m_ast_context,
m_ast_context->getTranslationUnitDecl(),
SourceLocation(),
SourceLocation(),
context.m_decl_name.getAsIdentifierInfo(),
type_source_info);
-
-
+
+
if (!typedef_decl)
return;
-
+
context.AddNamedDecl(typedef_decl);
-
+
if (method_decl->isInstance())
{
// self is a pointer to the object
-
+
QualType class_pointer_type = method_decl->getASTContext().getPointerType(class_qual_type);
-
+
TypeFromUser self_user_type(class_pointer_type.getAsOpaquePtr(),
&method_decl->getASTContext());
-
+
m_struct_vars->m_object_pointer_type = self_user_type;
}
}
@@ -1055,22 +1036,22 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
// scope and use its type.
// FIXME: This code is formally correct, but clang doesn't currently emit DW_AT_object_pointer
// for C++ so it hasn't actually been tested.
-
+
VariableList *vars = frame->GetVariableList(false);
-
+
lldb::VariableSP this_var = vars->FindVariable(ConstString("this"));
-
+
if (this_var &&
this_var->IsInScope(frame) &&
this_var->LocationIsValidForFrame (frame))
{
Type *this_type = this_var->GetType();
-
+
if (!this_type)
return;
-
+
ClangASTType pointee_type = this_type->GetClangForwardType().GetPointeeType();
-
+
if (pointee_type.IsValid())
{
if (log)
@@ -1078,89 +1059,89 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
ASTDumper ast_dumper(this_type->GetClangFullType());
log->Printf(" FEVD[%u] Adding type for $__lldb_objc_class: %s", current_id, ast_dumper.GetCString());
}
-
+
TypeFromUser class_user_type(pointee_type);
AddOneType(context, class_user_type, current_id);
-
-
+
+
TypeFromUser this_user_type(this_type->GetClangFullType());
m_struct_vars->m_object_pointer_type = this_user_type;
return;
}
}
}
-
+
return;
}
-
+
static ConstString g_lldb_objc_class_name ("$__lldb_objc_class");
if (name == g_lldb_objc_class_name)
{
// Clang is looking for the type of "*self"
-
+
if (!frame)
return;
-
+
SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction);
-
+
if (!sym_ctx.function)
return;
-
+
// Get the block that defines the function
Block *function_block = sym_ctx.GetFunctionBlock();
-
+
if (!function_block)
return;
-
+
clang::DeclContext *decl_context = function_block->GetClangDeclContext();
-
+
if (!decl_context)
return;
-
+
clang::ObjCMethodDecl *method_decl = llvm::dyn_cast<clang::ObjCMethodDecl>(decl_context);
-
+
if (method_decl)
{
ObjCInterfaceDecl* self_interface = method_decl->getClassInterface();
-
+
if (!self_interface)
return;
-
+
const clang::Type *interface_type = self_interface->getTypeForDecl();
-
+
if (!interface_type)
return; // This is unlikely, but we have seen crashes where this occurred
-
+
TypeFromUser class_user_type(QualType(interface_type, 0).getAsOpaquePtr(),
&method_decl->getASTContext());
-
+
if (log)
{
ASTDumper ast_dumper(interface_type);
log->Printf(" FEVD[%u] Adding type for $__lldb_objc_class: %s", current_id, ast_dumper.GetCString());
}
-
+
AddOneType(context, class_user_type, current_id);
-
+
if (method_decl->isInstanceMethod())
{
// self is a pointer to the object
-
+
QualType class_pointer_type = method_decl->getASTContext().getObjCObjectPointerType(QualType(interface_type, 0));
-
+
TypeFromUser self_user_type(class_pointer_type.getAsOpaquePtr(),
&method_decl->getASTContext());
-
+
m_struct_vars->m_object_pointer_type = self_user_type;
}
else
{
// self is a Class pointer
QualType class_type = method_decl->getASTContext().getObjCClassType();
-
+
TypeFromUser self_user_type(class_type.getAsOpaquePtr(),
&method_decl->getASTContext());
-
+
m_struct_vars->m_object_pointer_type = self_user_type;
}
@@ -1172,22 +1153,22 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
// claims to have an object pointer (through DW_AT_object_pointer?) but is not formally a
// method of the class. In that case, just look up the "self" variable in the the current
// scope and use its type.
-
+
VariableList *vars = frame->GetVariableList(false);
-
+
lldb::VariableSP self_var = vars->FindVariable(ConstString("self"));
-
+
if (self_var &&
- self_var->IsInScope(frame) &&
+ self_var->IsInScope(frame) &&
self_var->LocationIsValidForFrame (frame))
{
Type *self_type = self_var->GetType();
-
+
if (!self_type)
return;
-
+
ClangASTType self_clang_type = self_type->GetClangFullType();
-
+
if (self_clang_type.IsObjCClassType())
{
return;
@@ -1198,19 +1179,19 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
if (!self_clang_type)
return;
-
+
if (log)
{
ASTDumper ast_dumper(self_type->GetClangFullType());
log->Printf(" FEVD[%u] Adding type for $__lldb_objc_class: %s", current_id, ast_dumper.GetCString());
}
-
+
TypeFromUser class_user_type (self_clang_type);
-
+
AddOneType(context, class_user_type, current_id);
-
+
TypeFromUser self_user_type(self_type->GetClangFullType());
-
+
m_struct_vars->m_object_pointer_type = self_user_type;
return;
}
@@ -1219,66 +1200,66 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
return;
}
-
+
// any other $__lldb names should be weeded out now
if (!::strncmp(name_unique_cstr, "$__lldb", sizeof("$__lldb") - 1))
return;
-
+
do
{
if (!target)
break;
-
+
ClangASTContext *scratch_clang_ast_context = target->GetScratchClangASTContext();
-
+
if (!scratch_clang_ast_context)
break;
-
+
ASTContext *scratch_ast_context = scratch_clang_ast_context->getASTContext();
-
+
if (!scratch_ast_context)
break;
-
+
TypeDecl *ptype_type_decl = m_parser_vars->m_persistent_vars->GetPersistentType(name);
-
+
if (!ptype_type_decl)
break;
-
+
Decl *parser_ptype_decl = m_ast_importer->CopyDecl(m_ast_context, scratch_ast_context, ptype_type_decl);
-
+
if (!parser_ptype_decl)
break;
-
+
TypeDecl *parser_ptype_type_decl = dyn_cast<TypeDecl>(parser_ptype_decl);
-
+
if (!parser_ptype_type_decl)
break;
-
+
if (log)
log->Printf(" CEDM::FEVD[%u] Found persistent type %s", current_id, name.GetCString());
-
+
context.AddNamedDecl(parser_ptype_type_decl);
} while (0);
-
+
ClangExpressionVariableSP pvar_sp(m_parser_vars->m_persistent_vars->GetVariable(name));
-
+
if (pvar_sp)
{
AddOneVariable(context, pvar_sp, current_id);
return;
}
-
+
const char *reg_name(&name.GetCString()[1]);
-
+
if (m_parser_vars->m_exe_ctx.GetRegisterContext())
{
const RegisterInfo *reg_info(m_parser_vars->m_exe_ctx.GetRegisterContext()->GetRegisterInfoByName(reg_name));
-
+
if (reg_info)
{
if (log)
log->Printf(" CEDM::FEVD[%u] Found register %s", current_id, reg_info->name);
-
+
AddOneRegister(context, reg_info, current_id);
}
}
@@ -1288,11 +1269,11 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
ValueObjectSP valobj;
VariableSP var;
Error err;
-
+
if (frame && !namespace_decl)
{
- valobj = frame->GetValueForVariableExpressionPath(name_unique_cstr,
- eNoDynamicValues,
+ valobj = frame->GetValueForVariableExpressionPath(name_unique_cstr,
+ eNoDynamicValues,
StackFrame::eExpressionPathOptionCheckPtrVsMember ||
StackFrame::eExpressionPathOptionsAllowDirectIVarAccess ||
StackFrame::eExpressionPathOptionsNoFragileObjcIvar ||
@@ -1300,7 +1281,7 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
StackFrame::eExpressionPathOptionsNoSyntheticArrayRange,
var,
err);
-
+
// If we found a variable in scope, no need to pull up function names
if (err.Success() && var)
{
@@ -1309,7 +1290,7 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
return;
}
}
-
+
if (target)
{
var = FindGlobalVariable (*target,
@@ -1317,7 +1298,7 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
name,
&namespace_decl,
NULL);
-
+
if (var)
{
valobj = ValueObjectVariable::Create(target, var);
@@ -1326,19 +1307,19 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
return;
}
}
-
+
if (!context.m_found.variable)
{
const bool include_inlines = false;
const bool append = false;
-
+
if (namespace_decl && module_sp)
{
const bool include_symbols = false;
module_sp->FindFunctions(name,
&namespace_decl,
- eFunctionNameTypeBase,
+ eFunctionNameTypeBase,
include_symbols,
include_inlines,
append,
@@ -1347,63 +1328,63 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
else if (target && !namespace_decl)
{
const bool include_symbols = true;
-
+
// TODO Fix FindFunctions so that it doesn't return
// instance methods for eFunctionNameTypeBase.
-
+
target->GetImages().FindFunctions(name,
eFunctionNameTypeFull,
include_symbols,
include_inlines,
- append,
+ append,
sc_list);
}
-
+
if (sc_list.GetSize())
{
Symbol *extern_symbol = NULL;
Symbol *non_extern_symbol = NULL;
-
+
for (uint32_t index = 0, num_indices = sc_list.GetSize();
index < num_indices;
++index)
{
SymbolContext sym_ctx;
sc_list.GetContextAtIndex(index, sym_ctx);
-
+
if (sym_ctx.function)
{
clang::DeclContext *decl_ctx = sym_ctx.function->GetClangDeclContext();
-
+
if (!decl_ctx)
continue;
-
+
// Filter out class/instance methods.
if (dyn_cast<clang::ObjCMethodDecl>(decl_ctx))
continue;
if (dyn_cast<clang::CXXMethodDecl>(decl_ctx))
continue;
-
+
AddOneFunction(context, sym_ctx.function, NULL, current_id);
context.m_found.function_with_type_info = true;
context.m_found.function = true;
}
else if (sym_ctx.symbol)
{
- if (sym_ctx.symbol->GetType() == eSymbolTypeReExported)
+ if (sym_ctx.symbol->GetType() == eSymbolTypeReExported && target)
{
sym_ctx.symbol = sym_ctx.symbol->ResolveReExportedSymbol(*target);
if (sym_ctx.symbol == NULL)
continue;
}
-
+
if (sym_ctx.symbol->IsExternal())
extern_symbol = sym_ctx.symbol;
else
non_extern_symbol = sym_ctx.symbol;
}
}
-
+
if (!context.m_found.function_with_type_info)
{
if (extern_symbol)
@@ -1418,14 +1399,14 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
}
}
}
-
+
if (target && !context.m_found.variable && !namespace_decl)
{
- // We couldn't find a non-symbol variable for this. Now we'll hunt for a generic
+ // We couldn't find a non-symbol variable for this. Now we'll hunt for a generic
// data symbol, and -- if it is found -- treat it as a variable.
-
+
const Symbol *data_symbol = FindGlobalDataSymbol(*target, name);
-
+
if (data_symbol)
{
std::string warning("got name from symbols: ");
@@ -1440,43 +1421,43 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
}
}
-static clang_type_t
-MaybePromoteToBlockPointerType
-(
- ASTContext *ast_context,
- clang_type_t candidate_type
-)
-{
- if (!candidate_type)
- return candidate_type;
-
- QualType candidate_qual_type = QualType::getFromOpaquePtr(candidate_type);
-
- const PointerType *candidate_pointer_type = dyn_cast<PointerType>(candidate_qual_type);
-
- if (!candidate_pointer_type)
- return candidate_type;
-
- QualType pointee_qual_type = candidate_pointer_type->getPointeeType();
-
- const RecordType *pointee_record_type = dyn_cast<RecordType>(pointee_qual_type);
-
- if (!pointee_record_type)
- return candidate_type;
-
- RecordDecl *pointee_record_decl = pointee_record_type->getDecl();
-
- if (!pointee_record_decl->isRecord())
- return candidate_type;
-
- if (!pointee_record_decl->getName().startswith(llvm::StringRef("__block_literal_")))
- return candidate_type;
-
- QualType generic_function_type = ast_context->getFunctionNoProtoType(ast_context->UnknownAnyTy);
- QualType block_pointer_type = ast_context->getBlockPointerType(generic_function_type);
-
- return block_pointer_type.getAsOpaquePtr();
-}
+//static clang_type_t
+//MaybePromoteToBlockPointerType
+//(
+// ASTContext *ast_context,
+// clang_type_t candidate_type
+//)
+//{
+// if (!candidate_type)
+// return candidate_type;
+//
+// QualType candidate_qual_type = QualType::getFromOpaquePtr(candidate_type);
+//
+// const PointerType *candidate_pointer_type = dyn_cast<PointerType>(candidate_qual_type);
+//
+// if (!candidate_pointer_type)
+// return candidate_type;
+//
+// QualType pointee_qual_type = candidate_pointer_type->getPointeeType();
+//
+// const RecordType *pointee_record_type = dyn_cast<RecordType>(pointee_qual_type);
+//
+// if (!pointee_record_type)
+// return candidate_type;
+//
+// RecordDecl *pointee_record_decl = pointee_record_type->getDecl();
+//
+// if (!pointee_record_decl->isRecord())
+// return candidate_type;
+//
+// if (!pointee_record_decl->getName().startswith(llvm::StringRef("__block_literal_")))
+// return candidate_type;
+//
+// QualType generic_function_type = ast_context->getFunctionNoProtoType(ast_context->UnknownAnyTy);
+// QualType block_pointer_type = ast_context->getBlockPointerType(generic_function_type);
+//
+// return block_pointer_type.getAsOpaquePtr();
+//}
bool
ClangExpressionDeclMap::GetVariableValue (VariableSP &var,
@@ -1485,25 +1466,25 @@ ClangExpressionDeclMap::GetVariableValue (VariableSP &var,
TypeFromParser *parser_type)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
Type *var_type = var->GetType();
-
- if (!var_type)
+
+ if (!var_type)
{
if (log)
log->PutCString("Skipped a definition because it has no type");
return false;
}
-
+
ClangASTType var_clang_type = var_type->GetClangFullType();
-
+
if (!var_clang_type)
{
if (log)
log->PutCString("Skipped a definition because it has no Clang type");
return false;
}
-
+
ASTContext *ast = var_type->GetClangASTContext().getASTContext();
if (!ast)
@@ -1513,25 +1494,16 @@ ClangExpressionDeclMap::GetVariableValue (VariableSP &var,
return false;
}
//var_clang_type = MaybePromoteToBlockPointerType (ast, var_clang_type);
-
+
DWARFExpression &var_location_expr = var->LocationExpression();
-
- lldb::addr_t loclist_base_load_addr = LLDB_INVALID_ADDRESS;
-
- Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
- if (var_location_expr.IsLocationList())
- {
- SymbolContext var_sc;
- var->CalculateSymbolContext (&var_sc);
- loclist_base_load_addr = var_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress (target);
- }
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
Error err;
-
+
if (var->GetLocationIsConstantValueData())
{
DataExtractor const_value_extractor;
-
+
if (var_location_expr.GetExpressionData(const_value_extractor))
{
var_location = Value(const_value_extractor.GetDataStart(), const_value_extractor.GetByteSize());
@@ -1544,45 +1516,45 @@ ClangExpressionDeclMap::GetVariableValue (VariableSP &var,
return false;
}
}
-
+
ClangASTType type_to_use = GuardedCopyType(var_clang_type);
-
+
if (!type_to_use)
{
if (log)
log->Printf("Couldn't copy a variable's type into the parser's AST context");
-
+
return false;
}
-
+
if (parser_type)
*parser_type = TypeFromParser(type_to_use);
-
+
if (var_location.GetContextType() == Value::eContextTypeInvalid)
var_location.SetClangType(type_to_use);
-
+
if (var_location.GetValueType() == Value::eValueTypeFileAddress)
{
SymbolContext var_sc;
var->CalculateSymbolContext(&var_sc);
-
+
if (!var_sc.module_sp)
return false;
Address so_addr(var_location.GetScalar().ULongLong(), var_sc.module_sp->GetSectionList());
-
+
lldb::addr_t load_addr = so_addr.GetLoadAddress(target);
-
+
if (load_addr != LLDB_INVALID_ADDRESS)
{
var_location.GetScalar() = load_addr;
var_location.SetValueType(Value::eValueTypeLoadAddress);
}
}
-
+
if (user_type)
*user_type = TypeFromUser(var_clang_type);
-
+
return true;
}
@@ -1590,21 +1562,21 @@ void
ClangExpressionDeclMap::AddOneVariable (NameSearchContext &context, VariableSP var, ValueObjectSP valobj, unsigned int current_id)
{
assert (m_parser_vars.get());
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
TypeFromUser ut;
TypeFromParser pt;
Value var_location;
-
+
if (!GetVariableValue (var, var_location, &ut, &pt))
return;
-
+
clang::QualType parser_opaque_type = QualType::getFromOpaquePtr(pt.GetOpaqueQualType());
-
+
if (parser_opaque_type.isNull())
return;
-
+
if (const clang::Type *parser_type = parser_opaque_type.getTypePtr())
{
if (const TagType *tag_type = dyn_cast<TagType>(parser_type))
@@ -1612,8 +1584,8 @@ ClangExpressionDeclMap::AddOneVariable (NameSearchContext &context, VariableSP v
if (const ObjCObjectPointerType *objc_object_ptr_type = dyn_cast<ObjCObjectPointerType>(parser_type))
CompleteType(objc_object_ptr_type->getInterfaceDecl());
}
-
-
+
+
bool is_reference = pt.IsReferenceType();
NamedDecl *var_decl = NULL;
@@ -1621,11 +1593,11 @@ ClangExpressionDeclMap::AddOneVariable (NameSearchContext &context, VariableSP v
var_decl = context.AddVarDecl(pt);
else
var_decl = context.AddVarDecl(pt.GetLValueReferenceType());
-
+
std::string decl_name(context.m_decl_name.getAsString());
ConstString entity_name(decl_name.c_str());
ClangExpressionVariableSP entity(m_found_entities.CreateVariable (valobj));
-
+
assert (entity.get());
entity->EnableParserVars(GetParserID());
ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID());
@@ -1634,45 +1606,45 @@ ClangExpressionDeclMap::AddOneVariable (NameSearchContext &context, VariableSP v
parser_vars->m_llvm_value = NULL;
parser_vars->m_lldb_value = var_location;
parser_vars->m_lldb_var = var;
-
+
if (is_reference)
entity->m_flags |= ClangExpressionVariable::EVTypeIsReference;
-
+
if (log)
{
ASTDumper orig_dumper(ut.GetOpaqueQualType());
- ASTDumper ast_dumper(var_decl);
+ ASTDumper ast_dumper(var_decl);
log->Printf(" CEDM::FEVD[%u] Found variable %s, returned %s (original %s)", current_id, decl_name.c_str(), ast_dumper.GetCString(), orig_dumper.GetCString());
}
}
void
ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
- ClangExpressionVariableSP &pvar_sp,
+ ClangExpressionVariableSP &pvar_sp,
unsigned int current_id)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
TypeFromUser user_type (pvar_sp->GetTypeFromUser());
-
+
TypeFromParser parser_type (GuardedCopyType(user_type));
-
+
if (!parser_type.GetOpaqueQualType())
{
if (log)
log->Printf(" CEDM::FEVD[%u] Couldn't import type for pvar %s", current_id, pvar_sp->GetName().GetCString());
return;
}
-
+
NamedDecl *var_decl = context.AddVarDecl(parser_type.GetLValueReferenceType());
-
+
pvar_sp->EnableParserVars(GetParserID());
ClangExpressionVariable::ParserVars *parser_vars = pvar_sp->GetParserVars(GetParserID());
parser_vars->m_parser_type = parser_type;
parser_vars->m_named_decl = var_decl;
parser_vars->m_llvm_value = NULL;
parser_vars->m_lldb_value.Clear();
-
+
if (log)
{
ASTDumper ast_dumper(var_decl);
@@ -1681,59 +1653,59 @@ ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
}
void
-ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context,
+ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context,
const Symbol &symbol,
unsigned int current_id)
{
assert(m_parser_vars.get());
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
if (target == NULL)
return;
ASTContext *scratch_ast_context = target->GetScratchClangASTContext()->getASTContext();
-
+
TypeFromUser user_type (ClangASTContext::GetBasicType(scratch_ast_context, eBasicTypeVoid).GetPointerType().GetLValueReferenceType());
TypeFromParser parser_type (ClangASTContext::GetBasicType(m_ast_context, eBasicTypeVoid).GetPointerType().GetLValueReferenceType());
NamedDecl *var_decl = context.AddVarDecl(parser_type);
-
+
std::string decl_name(context.m_decl_name.getAsString());
ConstString entity_name(decl_name.c_str());
ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx.GetBestExecutionContextScope (),
- entity_name,
+ entity_name,
user_type,
m_parser_vars->m_target_info.byte_order,
m_parser_vars->m_target_info.address_byte_size));
assert (entity.get());
-
+
entity->EnableParserVars(GetParserID());
ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID());
const Address &symbol_address = symbol.GetAddress();
lldb::addr_t symbol_load_addr = symbol_address.GetLoadAddress(target);
-
+
//parser_vars->m_lldb_value.SetContext(Value::eContextTypeClangType, user_type.GetOpaqueQualType());
parser_vars->m_lldb_value.SetClangType(user_type);
parser_vars->m_lldb_value.GetScalar() = symbol_load_addr;
parser_vars->m_lldb_value.SetValueType(Value::eValueTypeLoadAddress);
-
+
parser_vars->m_parser_type = parser_type;
parser_vars->m_named_decl = var_decl;
parser_vars->m_llvm_value = NULL;
parser_vars->m_lldb_sym = &symbol;
-
+
if (log)
{
ASTDumper ast_dumper(var_decl);
-
+
log->Printf(" CEDM::FEVD[%u] Found variable %s, returned %s", current_id, decl_name.c_str(), ast_dumper.GetCString());
}
}
-bool
+bool
ClangExpressionDeclMap::ResolveUnknownTypes()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@@ -1746,82 +1718,82 @@ ClangExpressionDeclMap::ResolveUnknownTypes()
++index)
{
ClangExpressionVariableSP entity = m_found_entities.GetVariableAtIndex(index);
-
+
ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID());
-
+
if (entity->m_flags & ClangExpressionVariable::EVUnknownType)
{
const NamedDecl *named_decl = parser_vars->m_named_decl;
const VarDecl *var_decl = dyn_cast<VarDecl>(named_decl);
-
+
if (!var_decl)
{
if (log)
log->Printf("Entity of unknown type does not have a VarDecl");
return false;
}
-
+
if (log)
{
ASTDumper ast_dumper(const_cast<VarDecl*>(var_decl));
log->Printf("Variable of unknown type now has Decl %s", ast_dumper.GetCString());
}
-
+
QualType var_type = var_decl->getType();
TypeFromParser parser_type(var_type.getAsOpaquePtr(), &var_decl->getASTContext());
-
+
lldb::clang_type_t copied_type = m_ast_importer->CopyType(scratch_ast_context, &var_decl->getASTContext(), var_type.getAsOpaquePtr());
-
+
if (!copied_type)
- {
+ {
if (log)
log->Printf("ClangExpressionDeclMap::ResolveUnknownType - Couldn't import the type for a variable");
-
+
return (bool) lldb::ClangExpressionVariableSP();
}
-
+
TypeFromUser user_type(copied_type, scratch_ast_context);
-
+
// parser_vars->m_lldb_value.SetContext(Value::eContextTypeClangType, user_type.GetOpaqueQualType());
parser_vars->m_lldb_value.SetClangType(user_type);
parser_vars->m_parser_type = parser_type;
-
+
entity->SetClangType(user_type);
-
+
entity->m_flags &= ~(ClangExpressionVariable::EVUnknownType);
}
}
-
+
return true;
}
void
ClangExpressionDeclMap::AddOneRegister (NameSearchContext &context,
- const RegisterInfo *reg_info,
+ const RegisterInfo *reg_info,
unsigned int current_id)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
ClangASTType clang_type = ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (m_ast_context,
reg_info->encoding,
reg_info->byte_size * 8);
-
+
if (!clang_type)
{
if (log)
log->Printf(" Tried to add a type for %s, but couldn't get one", context.m_decl_name.getAsString().c_str());
return;
}
-
+
TypeFromParser parser_clang_type (clang_type);
-
+
NamedDecl *var_decl = context.AddVarDecl(parser_clang_type);
-
+
ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(),
m_parser_vars->m_target_info.byte_order,
m_parser_vars->m_target_info.address_byte_size));
assert (entity.get());
-
+
std::string decl_name(context.m_decl_name.getAsString());
entity->SetName (ConstString (decl_name.c_str()));
entity->SetRegisterInfo (reg_info);
@@ -1832,7 +1804,7 @@ ClangExpressionDeclMap::AddOneRegister (NameSearchContext &context,
parser_vars->m_llvm_value = NULL;
parser_vars->m_lldb_value.Clear();
entity->m_flags |= ClangExpressionVariable::EVBareRegister;
-
+
if (log)
{
ASTDumper ast_dumper(var_decl);
@@ -1847,9 +1819,9 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
unsigned int current_id)
{
assert (m_parser_vars.get());
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
NamedDecl *function_decl = NULL;
const Address *fun_address = NULL;
ClangASTType function_clang_type;
@@ -1859,30 +1831,30 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
if (function)
{
Type *function_type = function->GetType();
-
+
if (!function_type)
{
if (log)
log->PutCString(" Skipped a function because it has no type");
return;
}
-
+
function_clang_type = function_type->GetClangFullType();
-
+
if (!function_clang_type)
{
if (log)
log->PutCString(" Skipped a function because it has no Clang type");
return;
}
-
+
fun_address = &function->GetAddressRange().GetBaseAddress();
-
+
ClangASTType copied_function_type = GuardedCopyType(function_clang_type);
if (copied_function_type)
{
function_decl = context.AddFunDecl(copied_function_type);
-
+
if (!function_decl)
{
if (log)
@@ -1891,7 +1863,7 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
function_type->GetName().GetCString(),
function_type->GetID());
}
-
+
return;
}
}
@@ -1904,7 +1876,7 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
function_type->GetName().GetCString(),
function_type->GetID());
}
-
+
return;
}
}
@@ -1920,11 +1892,11 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
log->PutCString(" AddOneFunction called with no function and no symbol");
return;
}
-
+
Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
lldb::addr_t load_addr = fun_address->GetCallableLoadAddress(target, is_indirect_function);
-
+
ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx.GetBestExecutionContextScope (),
m_parser_vars->m_target_info.byte_order,
m_parser_vars->m_target_info.address_byte_size));
@@ -1936,7 +1908,7 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
entity->EnableParserVars(GetParserID());
ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID());
-
+
if (load_addr != LLDB_INVALID_ADDRESS)
{
parser_vars->m_lldb_value.SetValueType(Value::eValueTypeLoadAddress);
@@ -1945,25 +1917,25 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
else
{
// We have to try finding a file address.
-
+
lldb::addr_t file_addr = fun_address->GetFileAddress();
-
+
parser_vars->m_lldb_value.SetValueType(Value::eValueTypeFileAddress);
parser_vars->m_lldb_value.GetScalar() = file_addr;
}
-
+
parser_vars->m_named_decl = function_decl;
parser_vars->m_llvm_value = NULL;
-
+
if (log)
{
ASTDumper ast_dumper(function_decl);
-
+
StreamString ss;
-
+
fun_address->Dump(&ss, m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(), Address::DumpStyleResolvedDescription);
-
+
log->Printf(" CEDM::FEVD[%u] Found %s function %s (description %s), returned %s",
current_id,
(function ? "specific" : "generic"),
@@ -1978,14 +1950,14 @@ ClangExpressionDeclMap::CopyClassType(TypeFromUser &ut,
unsigned int current_id)
{
ClangASTType copied_clang_type = GuardedCopyType(ut);
-
+
if (!copied_clang_type)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (log)
log->Printf("ClangExpressionDeclMap::CopyClassType - Couldn't import the type");
-
+
return TypeFromParser();
}
@@ -1993,21 +1965,21 @@ ClangExpressionDeclMap::CopyClassType(TypeFromUser &ut,
{
ClangASTType void_clang_type = ClangASTContext::GetBasicType(m_ast_context, eBasicTypeVoid);
ClangASTType void_ptr_clang_type = void_clang_type.GetPointerType();
-
+
ClangASTType method_type = ClangASTContext::CreateFunctionType (m_ast_context,
void_clang_type,
&void_ptr_clang_type,
1,
false,
copied_clang_type.GetTypeQualifiers());
-
+
const bool is_virtual = false;
const bool is_static = false;
const bool is_inline = false;
const bool is_explicit = false;
const bool is_attr_used = true;
const bool is_artificial = false;
-
+
copied_clang_type.AddMethodToCXXRecordType ("$__lldb_expr",
method_type,
lldb::eAccessPublic,
@@ -2018,26 +1990,26 @@ ClangExpressionDeclMap::CopyClassType(TypeFromUser &ut,
is_attr_used,
is_artificial);
}
-
+
return TypeFromParser(copied_clang_type);
}
-void
-ClangExpressionDeclMap::AddOneType(NameSearchContext &context,
+void
+ClangExpressionDeclMap::AddOneType(NameSearchContext &context,
TypeFromUser &ut,
unsigned int current_id)
{
ClangASTType copied_clang_type = GuardedCopyType(ut);
-
+
if (!copied_clang_type)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (log)
log->Printf("ClangExpressionDeclMap::AddOneType - Couldn't import the type");
-
+
return;
}
-
+
context.AddTypeDecl(copied_clang_type);
}
diff --git a/source/Expression/ClangExpressionParser.cpp b/source/Expression/ClangExpressionParser.cpp
index 615f29fd0c76..f32ca3ae216c 100644
--- a/source/Expression/ClangExpressionParser.cpp
+++ b/source/Expression/ClangExpressionParser.cpp
@@ -15,6 +15,7 @@
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
@@ -24,6 +25,9 @@
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Expression/IRInterpreter.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
@@ -55,11 +59,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/TargetSelect.h"
-#if defined (USE_STANDARD_JIT)
-#include "llvm/ExecutionEngine/JIT.h"
-#else
#include "llvm/ExecutionEngine/MCJIT.h"
-#endif
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/ErrorHandling.h"
@@ -88,89 +88,8 @@ std::string GetBuiltinIncludePath(const char *Argv0) {
llvm::sys::path::append(P, "lib", "clang", CLANG_VERSION_STRING,
"include");
}
-
- return P.str();
-}
-
-
-//===----------------------------------------------------------------------===//
-// Main driver for Clang
-//===----------------------------------------------------------------------===//
-
-static void LLVMErrorHandler(void *UserData, const std::string &Message) {
- DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
-
- Diags.Report(diag::err_fe_error_backend) << Message;
-
- // We cannot recover from llvm errors.
- assert(0);
-}
-static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
- using namespace clang::frontend;
-
- switch (CI.getFrontendOpts().ProgramAction) {
- default:
- llvm_unreachable("Invalid program action!");
-
- case ASTDump: return new ASTDumpAction();
- case ASTPrint: return new ASTPrintAction();
- case ASTView: return new ASTViewAction();
- case DumpRawTokens: return new DumpRawTokensAction();
- case DumpTokens: return new DumpTokensAction();
- case EmitAssembly: return new EmitAssemblyAction();
- case EmitBC: return new EmitBCAction();
- case EmitHTML: return new HTMLPrintAction();
- case EmitLLVM: return new EmitLLVMAction();
- case EmitLLVMOnly: return new EmitLLVMOnlyAction();
- case EmitCodeGenOnly: return new EmitCodeGenOnlyAction();
- case EmitObj: return new EmitObjAction();
- case FixIt: return new FixItAction();
- case GeneratePCH: return new GeneratePCHAction();
- case GeneratePTH: return new GeneratePTHAction();
- case InitOnly: return new InitOnlyAction();
- case ParseSyntaxOnly: return new SyntaxOnlyAction();
-
- case PluginAction: {
- for (FrontendPluginRegistry::iterator it =
- FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end();
- it != ie; ++it) {
- if (it->getName() == CI.getFrontendOpts().ActionName) {
- llvm::OwningPtr<PluginASTAction> P(it->instantiate());
- if (!P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs))
- return 0;
- return P.take();
- }
- }
-
- CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name)
- << CI.getFrontendOpts().ActionName;
- return 0;
- }
-
- case PrintDeclContext: return new DeclContextPrintAction();
- case PrintPreamble: return new PrintPreambleAction();
- case PrintPreprocessedInput: return new PrintPreprocessedAction();
- case RewriteMacros: return new RewriteMacrosAction();
- case RewriteObjC: return new RewriteObjCAction();
- case RewriteTest: return new RewriteTestAction();
- //case RunAnalysis: return new AnalysisAction();
- case RunPreprocessorOnly: return new PreprocessOnlyAction();
- }
-}
-
-static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
- // Create the underlying action.
- FrontendAction *Act = CreateFrontendBaseAction(CI);
- if (!Act)
- return 0;
-
- // If there are any AST files to merge, create a frontend action
- // adaptor to perform the merge.
- if (!CI.getFrontendOpts().ASTMergeFiles.empty())
- Act = new ASTMergeAction(Act, CI.getFrontendOpts().ASTMergeFiles);
-
- return Act;
+ return P.str();
}
//===----------------------------------------------------------------------===//
@@ -178,30 +97,21 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
//===----------------------------------------------------------------------===//
ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
- ClangExpression &expr) :
+ ClangExpression &expr,
+ bool generate_debug_info) :
m_expr (expr),
m_compiler (),
m_code_generator ()
{
- // Initialize targets first, so that --version shows registered targets.
- static struct InitializeLLVM {
- InitializeLLVM() {
- llvm::InitializeAllTargets();
- llvm::InitializeAllAsmPrinters();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllDisassemblers();
- }
- } InitializeLLVM;
-
// 1. Create a new compiler instance.
- m_compiler.reset(new CompilerInstance());
-
+ m_compiler.reset(new CompilerInstance());
+
// 2. Install the target.
lldb::TargetSP target_sp;
if (exe_scope)
target_sp = exe_scope->CalculateTarget();
-
+
// TODO: figure out what to really do when we don't have a valid target.
// Sometimes this will be ok to just use the host target triple (when we
// evaluate say "2+3", but other expressions like breakpoint conditions
@@ -210,48 +120,40 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
if (target_sp && target_sp->GetArchitecture().IsValid())
{
std::string triple = target_sp->GetArchitecture().GetTriple().str();
-
- int dash_count = 0;
- for (size_t i = 0; i < triple.size(); ++i)
- {
- if (triple[i] == '-')
- dash_count++;
- if (dash_count == 3)
- {
- triple.resize(i);
- break;
- }
- }
-
m_compiler->getTargetOpts().Triple = triple;
}
else
{
m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
}
-
+
if (target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86 ||
target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86_64)
{
m_compiler->getTargetOpts().Features.push_back("+sse");
m_compiler->getTargetOpts().Features.push_back("+sse2");
}
-
- if (m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos)
+
+ // Any arm32 iOS environment, but not on arm64
+ if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos &&
+ m_compiler->getTargetOpts().Triple.find("arm") != std::string::npos &&
+ m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos)
+ {
m_compiler->getTargetOpts().ABI = "apcs-gnu";
-
+ }
+
m_compiler->createDiagnostics();
-
+
// Create the target instance.
- m_compiler->setTarget(TargetInfo::CreateTargetInfo(m_compiler->getDiagnostics(),
- &m_compiler->getTargetOpts()));
-
+ m_compiler->setTarget(TargetInfo::CreateTargetInfo(
+ m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts));
+
assert (m_compiler->hasTarget());
-
+
// 3. Set options.
-
+
lldb::LanguageType language = expr.Language();
-
+
switch (language)
{
case lldb::eLanguageTypeC:
@@ -272,20 +174,20 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
m_compiler->getLangOpts().CPlusPlus11 = true;
break;
}
-
+
m_compiler->getLangOpts().Bool = true;
m_compiler->getLangOpts().WChar = true;
m_compiler->getLangOpts().Blocks = true;
m_compiler->getLangOpts().DebuggerSupport = true; // Features specifically for debugger clients
if (expr.DesiredResultType() == ClangExpression::eResultTypeId)
m_compiler->getLangOpts().DebuggerCastResultToId = true;
-
+
// Spell checking is a nice feature, but it ends up completing a
// lot of types that we didn't strictly speaking need to complete.
// As a result, we spend a long time parsing and importing debug
// information.
- m_compiler->getLangOpts().SpellChecking = false;
-
+ m_compiler->getLangOpts().SpellChecking = false;
+
lldb::ProcessSP process_sp;
if (exe_scope)
process_sp = exe_scope->CalculateProcess();
@@ -298,7 +200,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::MacOSX, VersionTuple(10, 7));
else
m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::FragileMacOSX, VersionTuple(10, 7));
-
+
if (process_sp->GetObjCLanguageRuntime()->HasNewLiteralsAndIndexing())
m_compiler->getLangOpts().DebuggerObjCLiteral = true;
}
@@ -307,62 +209,67 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
m_compiler->getLangOpts().ThreadsafeStatics = false;
m_compiler->getLangOpts().AccessControl = false; // Debuggers get universal access
m_compiler->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name
-
+
// Set CodeGen options
m_compiler->getCodeGenOpts().EmitDeclMetadata = true;
m_compiler->getCodeGenOpts().InstrumentFunctions = false;
m_compiler->getCodeGenOpts().DisableFPElim = true;
m_compiler->getCodeGenOpts().OmitLeafFramePointer = false;
-
+ if (generate_debug_info)
+ m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::FullDebugInfo);
+ else
+ m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::NoDebugInfo);
+
// Disable some warnings.
- m_compiler->getDiagnostics().setDiagnosticGroupMapping("unused-value", clang::diag::MAP_IGNORE, SourceLocation());
- m_compiler->getDiagnostics().setDiagnosticGroupMapping("odr", clang::diag::MAP_IGNORE, SourceLocation());
-
+ m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError,
+ "unused-value", clang::diag::Severity::Ignored, SourceLocation());
+ m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError,
+ "odr", clang::diag::Severity::Ignored, SourceLocation());
+
// Inform the target of the language options
//
// FIXME: We shouldn't need to do this, the target should be immutable once
// created. This complexity should be lifted elsewhere.
- m_compiler->getTarget().setForcedLangOptions(m_compiler->getLangOpts());
-
+ m_compiler->getTarget().adjust(m_compiler->getLangOpts());
+
// 4. Set up the diagnostic buffer for reporting errors
-
+
m_compiler->getDiagnostics().setClient(new clang::TextDiagnosticBuffer);
-
+
// 5. Set up the source management objects inside the compiler
-
+
clang::FileSystemOptions file_system_options;
m_file_manager.reset(new clang::FileManager(file_system_options));
-
+
if (!m_compiler->hasSourceManager())
m_compiler->createSourceManager(*m_file_manager.get());
-
+
m_compiler->createFileManager();
- m_compiler->createPreprocessor();
-
- // 6. Most of this we get from the CompilerInstance, but we
+ m_compiler->createPreprocessor(TU_Complete);
+
+ // 6. Most of this we get from the CompilerInstance, but we
// also want to give the context an ExternalASTSource.
m_selector_table.reset(new SelectorTable());
m_builtin_context.reset(new Builtin::Context());
-
+
std::unique_ptr<clang::ASTContext> ast_context(new ASTContext(m_compiler->getLangOpts(),
m_compiler->getSourceManager(),
- &m_compiler->getTarget(),
m_compiler->getPreprocessor().getIdentifierTable(),
*m_selector_table.get(),
- *m_builtin_context.get(),
- 0));
-
+ *m_builtin_context.get()));
+ ast_context->InitBuiltinTypes(m_compiler->getTarget());
+
ClangExpressionDeclMap *decl_map = m_expr.DeclMap();
-
+
if (decl_map)
{
- llvm::OwningPtr<clang::ExternalASTSource> ast_source(decl_map->CreateProxy());
+ llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source(decl_map->CreateProxy());
decl_map->InstallASTContext(ast_context.get());
ast_context->setExternalSource(ast_source);
}
-
+
m_compiler->setASTContext(ast_context.release());
-
+
std::string module_name("$__lldb_module");
m_llvm_context.reset(new LLVMContext());
@@ -381,34 +288,77 @@ unsigned
ClangExpressionParser::Parse (Stream &stream)
{
TextDiagnosticBuffer *diag_buf = static_cast<TextDiagnosticBuffer*>(m_compiler->getDiagnostics().getClient());
-
+
diag_buf->FlushDiagnostics (m_compiler->getDiagnostics());
-
- MemoryBuffer *memory_buffer = MemoryBuffer::getMemBufferCopy(m_expr.Text(), __FUNCTION__);
- m_compiler->getSourceManager().createMainFileIDForMemBuffer (memory_buffer);
-
+
+ const char *expr_text = m_expr.Text();
+
+ clang::SourceManager &SourceMgr = m_compiler->getSourceManager();
+ bool created_main_file = false;
+ if (m_compiler->getCodeGenOpts().getDebugInfo() == CodeGenOptions::FullDebugInfo)
+ {
+ std::string temp_source_path;
+
+ FileSpec tmpdir_file_spec;
+ if (HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
+ {
+ tmpdir_file_spec.AppendPathComponent("expr.XXXXXX");
+ temp_source_path = std::move(tmpdir_file_spec.GetPath());
+ }
+ else
+ {
+ temp_source_path = "/tmp/expr.XXXXXX";
+ }
+
+ if (mktemp(&temp_source_path[0]))
+ {
+ lldb_private::File file (temp_source_path.c_str(),
+ File::eOpenOptionWrite | File::eOpenOptionCanCreateNewOnly,
+ lldb::eFilePermissionsFileDefault);
+ const size_t expr_text_len = strlen(expr_text);
+ size_t bytes_written = expr_text_len;
+ if (file.Write(expr_text, bytes_written).Success())
+ {
+ if (bytes_written == expr_text_len)
+ {
+ file.Close();
+ SourceMgr.setMainFileID(SourceMgr.createFileID(
+ m_file_manager->getFile(temp_source_path),
+ SourceLocation(), SrcMgr::C_User));
+ created_main_file = true;
+ }
+ }
+ }
+ }
+
+ if (!created_main_file)
+ {
+ std::unique_ptr<MemoryBuffer> memory_buffer = MemoryBuffer::getMemBufferCopy(expr_text, __FUNCTION__);
+ SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(memory_buffer)));
+ }
+
diag_buf->BeginSourceFile(m_compiler->getLangOpts(), &m_compiler->getPreprocessor());
-
+
ASTConsumer *ast_transformer = m_expr.ASTTransformer(m_code_generator.get());
-
+
if (ast_transformer)
ParseAST(m_compiler->getPreprocessor(), ast_transformer, m_compiler->getASTContext());
- else
- ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(), m_compiler->getASTContext());
-
+ else
+ ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(), m_compiler->getASTContext());
+
diag_buf->EndSourceFile();
-
+
TextDiagnosticBuffer::const_iterator diag_iterator;
-
+
int num_errors = 0;
-
+
for (diag_iterator = diag_buf->warn_begin();
diag_iterator != diag_buf->warn_end();
++diag_iterator)
stream.Printf("warning: %s\n", (*diag_iterator).second.c_str());
-
+
num_errors = 0;
-
+
for (diag_iterator = diag_buf->err_begin();
diag_iterator != diag_buf->err_end();
++diag_iterator)
@@ -416,12 +366,12 @@ ClangExpressionParser::Parse (Stream &stream)
num_errors++;
stream.Printf("error: %s\n", (*diag_iterator).second.c_str());
}
-
+
for (diag_iterator = diag_buf->note_begin();
diag_iterator != diag_buf->note_end();
++diag_iterator)
stream.Printf("note: %s\n", (*diag_iterator).second.c_str());
-
+
if (!num_errors)
{
if (m_expr.DeclMap() && !m_expr.DeclMap()->ResolveUnknownTypes())
@@ -430,7 +380,7 @@ ClangExpressionParser::Parse (Stream &stream)
num_errors++;
}
}
-
+
return num_errors;
}
@@ -441,21 +391,21 @@ static bool FindFunctionInModule (ConstString &mangled_name,
for (llvm::Module::iterator fi = module->getFunctionList().begin(), fe = module->getFunctionList().end();
fi != fe;
++fi)
- {
+ {
if (fi->getName().str().find(orig_name) != std::string::npos)
{
mangled_name.SetCString(fi->getName().str().c_str());
return true;
}
}
-
+
return false;
}
Error
-ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
+ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
lldb::addr_t &func_end,
- std::unique_ptr<IRExecutionUnit> &execution_unit_ap,
+ std::shared_ptr<IRExecutionUnit> &execution_unit_sp,
ExecutionContext &exe_ctx,
bool &can_interpret,
ExecutionPolicy execution_policy)
@@ -464,24 +414,22 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
func_end = LLDB_INVALID_ADDRESS;
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
- std::unique_ptr<llvm::ExecutionEngine> execution_engine_ap;
-
Error err;
-
- std::unique_ptr<llvm::Module> module_ap (m_code_generator->ReleaseModule());
- if (!module_ap.get())
+ std::unique_ptr<llvm::Module> llvm_module_ap (m_code_generator->ReleaseModule());
+
+ if (!llvm_module_ap.get())
{
err.SetErrorToGenericError();
err.SetErrorString("IR doesn't contain a module");
return err;
}
-
+
// Find the actual name of the function (it's often mangled somehow)
-
+
ConstString function_name;
-
- if (!FindFunctionInModule(function_name, module_ap.get(), m_expr.FunctionName()))
+
+ if (!FindFunctionInModule(function_name, llvm_module_ap.get(), m_expr.FunctionName()))
{
err.SetErrorToGenericError();
err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName());
@@ -492,54 +440,54 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
if (log)
log->Printf("Found function %s for %s", function_name.AsCString(), m_expr.FunctionName());
}
-
- m_execution_unit.reset(new IRExecutionUnit(m_llvm_context, // handed off here
- module_ap, // handed off here
- function_name,
- exe_ctx.GetTargetSP(),
- m_compiler->getTargetOpts().Features));
-
+
+ execution_unit_sp.reset(new IRExecutionUnit (m_llvm_context, // handed off here
+ llvm_module_ap, // handed off here
+ function_name,
+ exe_ctx.GetTargetSP(),
+ m_compiler->getTargetOpts().Features));
+
ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); // result can be NULL
-
+
if (decl_map)
{
Stream *error_stream = NULL;
Target *target = exe_ctx.GetTargetPtr();
if (target)
error_stream = target->GetDebugger().GetErrorFile().get();
-
+
IRForTarget ir_for_target(decl_map,
m_expr.NeedsVariableResolution(),
- *m_execution_unit,
+ *execution_unit_sp,
error_stream,
function_name.AsCString());
-
- bool ir_can_run = ir_for_target.runOnModule(*m_execution_unit->GetModule());
-
+
+ bool ir_can_run = ir_for_target.runOnModule(*execution_unit_sp->GetModule());
+
Error interpret_error;
-
- can_interpret = IRInterpreter::CanInterpret(*m_execution_unit->GetModule(), *m_execution_unit->GetFunction(), interpret_error);
-
+
+ can_interpret = IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), interpret_error);
+
Process *process = exe_ctx.GetProcessPtr();
-
+
if (!ir_can_run)
{
err.SetErrorString("The expression could not be prepared to run in the target");
return err;
}
-
+
if (!can_interpret && execution_policy == eExecutionPolicyNever)
{
err.SetErrorStringWithFormat("Can't run the expression locally: %s", interpret_error.AsCString());
return err;
}
-
+
if (!process && execution_policy == eExecutionPolicyAlways)
{
err.SetErrorString("Expression needed to run in the target, but the target can't be run");
return err;
}
-
+
if (execution_policy == eExecutionPolicyAlways || !can_interpret)
{
if (m_expr.NeedsValidation() && process)
@@ -547,44 +495,50 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
if (!process->GetDynamicCheckers())
{
DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions();
-
+
StreamString install_errors;
-
+
if (!dynamic_checkers->Install(install_errors, exe_ctx))
{
if (install_errors.GetString().empty())
err.SetErrorString ("couldn't install checkers, unknown error");
else
err.SetErrorString (install_errors.GetString().c_str());
-
+
return err;
}
-
+
process->SetDynamicCheckers(dynamic_checkers);
-
+
if (log)
log->Printf("== [ClangUserExpression::Evaluate] Finished installing dynamic checkers ==");
}
-
+
IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), function_name.AsCString());
-
- if (!ir_dynamic_checks.runOnModule(*m_execution_unit->GetModule()))
+
+ if (!ir_dynamic_checks.runOnModule(*execution_unit_sp->GetModule()))
{
err.SetErrorToGenericError();
err.SetErrorString("Couldn't add dynamic checks to the expression");
return err;
}
}
-
- m_execution_unit->GetRunnableInfo(err, func_addr, func_end);
+
+ execution_unit_sp->GetRunnableInfo(err, func_addr, func_end);
}
}
else
{
- m_execution_unit->GetRunnableInfo(err, func_addr, func_end);
+ execution_unit_sp->GetRunnableInfo(err, func_addr, func_end);
}
-
- execution_unit_ap.reset (m_execution_unit.release());
-
+
return err;
}
+
+bool
+ClangExpressionParser::GetGenerateDebugInfo () const
+{
+ if (m_compiler)
+ return m_compiler->getCodeGenOpts().getDebugInfo() == CodeGenOptions::FullDebugInfo;
+ return false;
+}
diff --git a/source/Expression/ClangExpressionVariable.cpp b/source/Expression/ClangExpressionVariable.cpp
index 0d355ce341c9..c3eae41473e9 100644
--- a/source/Expression/ClangExpressionVariable.cpp
+++ b/source/Expression/ClangExpressionVariable.cpp
@@ -8,11 +8,6 @@
//===----------------------------------------------------------------------===//
#include "lldb/Expression/ClangExpressionVariable.h"
-
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "clang/AST/ASTContext.h"
#include "lldb/Core/ConstString.h"
#include "lldb/Core/DataExtractor.h"
@@ -44,17 +39,17 @@ ClangExpressionVariable::ClangExpressionVariable (const lldb::ValueObjectSP &val
//----------------------------------------------------------------------
/// Return the variable's size in bytes
//----------------------------------------------------------------------
-size_t
+size_t
ClangExpressionVariable::GetByteSize ()
{
return m_frozen_sp->GetByteSize();
-}
+}
const ConstString &
ClangExpressionVariable::GetName ()
{
return m_frozen_sp->GetName();
-}
+}
lldb::ValueObjectSP
ClangExpressionVariable::GetValueObject()
@@ -78,13 +73,13 @@ ClangASTType
ClangExpressionVariable::GetClangType()
{
return m_frozen_sp->GetClangType();
-}
+}
void
ClangExpressionVariable::SetClangType(const ClangASTType &clang_type)
{
m_frozen_sp->GetValue().SetClangType(clang_type);
-}
+}
TypeFromUser
@@ -92,7 +87,7 @@ ClangExpressionVariable::GetTypeFromUser()
{
TypeFromUser tfu (m_frozen_sp->GetClangType());
return tfu;
-}
+}
uint8_t *
ClangExpressionVariable::GetValueBytes()
@@ -130,7 +125,7 @@ ClangExpressionVariable::TransferAddress (bool force)
if (m_frozen_sp.get() == NULL)
return;
-
+
if (force || (m_frozen_sp->GetLiveAddress() == LLDB_INVALID_ADDRESS))
m_frozen_sp->SetLiveAddress(m_live_sp->GetLiveAddress());
}
diff --git a/source/Expression/ClangFunction.cpp b/source/Expression/ClangFunction.cpp
index e707c60ffced..27afba2898ab 100644
--- a/source/Expression/ClangFunction.cpp
+++ b/source/Expression/ClangFunction.cpp
@@ -22,18 +22,20 @@
#include "llvm/IR/Module.h"
// Project includes
-#include "lldb/Expression/ASTStructExtractor.h"
-#include "lldb/Expression/ClangExpressionParser.h"
-#include "lldb/Expression/ClangFunction.h"
-#include "lldb/Expression/IRExecutionUnit.h"
-#include "lldb/Symbol/Type.h"
#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/State.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Expression/ASTStructExtractor.h"
+#include "lldb/Expression/ClangExpressionParser.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Type.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -41,7 +43,6 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
-#include "lldb/Core/Log.h"
using namespace lldb_private;
@@ -53,8 +54,13 @@ ClangFunction::ClangFunction
ExecutionContextScope &exe_scope,
const ClangASTType &return_type,
const Address& functionAddress,
- const ValueList &arg_value_list
+ const ValueList &arg_value_list,
+ const char *name
) :
+ m_parser(),
+ m_execution_unit_sp(),
+ m_jit_module_wp(),
+ m_name (name ? name : "<unknown>"),
m_function_ptr (NULL),
m_function_addr (functionAddress),
m_function_return_type(return_type),
@@ -75,8 +81,10 @@ ClangFunction::ClangFunction
ExecutionContextScope &exe_scope,
Function &function,
ClangASTContext *ast_context,
- const ValueList &arg_value_list
+ const ValueList &arg_value_list,
+ const char *name
) :
+ m_name (name ? name : "<unknown>"),
m_function_ptr (&function),
m_function_addr (),
m_function_return_type (),
@@ -87,7 +95,7 @@ ClangFunction::ClangFunction
m_compiled (false),
m_JITted (false)
{
- m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess());
+ m_jit_process_wp = exe_scope.CalculateProcess();
// Can't make a ClangFunction without a process.
assert (m_jit_process_wp.lock());
@@ -100,6 +108,13 @@ ClangFunction::ClangFunction
//----------------------------------------------------------------------
ClangFunction::~ClangFunction()
{
+ lldb::ProcessSP process_sp (m_jit_process_wp.lock());
+ if (process_sp)
+ {
+ lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock());
+ if (jit_module_sp)
+ process_sp->GetTarget().GetImages().Remove(jit_module_sp);
+ }
}
unsigned
@@ -173,7 +188,7 @@ ClangFunction::CompileFunction (Stream &errors)
}
else
{
- errors.Printf("Could not determine type of input value %zu.", i);
+ errors.Printf("Could not determine type of input value %" PRIu64 ".", (uint64_t)i);
return 1;
}
}
@@ -222,7 +237,8 @@ ClangFunction::CompileFunction (Stream &errors)
lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());
if (jit_process_sp)
{
- m_parser.reset(new ClangExpressionParser(jit_process_sp.get(), *this));
+ const bool generate_debug_info = true;
+ m_parser.reset(new ClangExpressionParser(jit_process_sp.get(), *this, generate_debug_info));
num_errors = m_parser->Parse (errors);
}
@@ -263,7 +279,7 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors)
Error jit_error (m_parser->PrepareForExecution (m_jit_start_addr,
m_jit_end_addr,
- m_execution_unit_ap,
+ m_execution_unit_sp,
exe_ctx,
can_interpret,
eExecutionPolicyAlways));
@@ -271,8 +287,22 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors)
if (!jit_error.Success())
return false;
+ if (m_parser->GetGenerateDebugInfo())
+ {
+ lldb::ModuleSP jit_module_sp ( m_execution_unit_sp->GetJITModule());
+
+ if (jit_module_sp)
+ {
+ ConstString const_func_name(FunctionName());
+ FileSpec jit_file;
+ jit_file.GetFilename() = const_func_name;
+ jit_module_sp->SetFileSpecAndObjectName (jit_file, ConstString());
+ m_jit_module_wp = jit_module_sp;
+ process->GetTarget().GetImages().Append(jit_module_sp);
+ }
+ }
if (process && m_jit_start_addr)
- m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
+ m_jit_process_wp = process->shared_from_this();
m_JITted = true;
@@ -304,7 +334,7 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx,
Error error;
using namespace clang;
- ExecutionResults return_value = eExecutionSetupError;
+ lldb::ExpressionResults return_value = lldb::eExpressionSetupError;
Process *process = exe_ctx.GetProcessPtr();
@@ -344,7 +374,7 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx,
size_t num_args = arg_values.GetSize();
if (num_args != m_arg_values.GetSize())
{
- errors.Printf ("Wrong number of arguments - was: %zu should be: %zu", num_args, m_arg_values.GetSize());
+ errors.Printf ("Wrong number of arguments - was: %" PRIu64 " should be: %" PRIu64 "", (uint64_t)num_args, (uint64_t)m_arg_values.GetSize());
return false;
}
@@ -401,7 +431,7 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
if (log)
- log->Printf("-- [ClangFunction::GetThreadPlanToCallFunction] Creating thread plan to call function --");
+ log->Printf("-- [ClangFunction::GetThreadPlanToCallFunction] Creating thread plan to call function \"%s\" --", m_name.c_str());
// FIXME: Use the errors Stream for better error reporting.
Thread *thread = exe_ctx.GetThreadPtr();
@@ -438,7 +468,7 @@ ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t arg
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
if (log)
- log->Printf("-- [ClangFunction::FetchFunctionResults] Fetching function results --");
+ log->Printf("-- [ClangFunction::FetchFunctionResults] Fetching function results for \"%s\"--", m_name.c_str());
Process *process = exe_ctx.GetProcessPtr();
@@ -472,7 +502,7 @@ ClangFunction::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_
exe_ctx.GetProcessRef().DeallocateMemory(args_addr);
}
-ExecutionResults
+lldb::ExpressionResults
ClangFunction::ExecuteFunction(
ExecutionContext &exe_ctx,
lldb::addr_t *args_addr_ptr,
@@ -481,7 +511,7 @@ ClangFunction::ExecuteFunction(
Value &results)
{
using namespace clang;
- ExecutionResults return_value = eExecutionSetupError;
+ lldb::ExpressionResults return_value = lldb::eExpressionSetupError;
// ClangFunction::ExecuteFunction execution is always just to get the result. Do make sure we ignore
// breakpoints, unwind on error, and don't try to debug it.
@@ -498,27 +528,27 @@ ClangFunction::ExecuteFunction(
args_addr = LLDB_INVALID_ADDRESS;
if (CompileFunction(errors) != 0)
- return eExecutionSetupError;
+ return lldb::eExpressionSetupError;
if (args_addr == LLDB_INVALID_ADDRESS)
{
if (!InsertFunction(exe_ctx, args_addr, errors))
- return eExecutionSetupError;
+ return lldb::eExpressionSetupError;
}
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
if (log)
- log->Printf("== [ClangFunction::ExecuteFunction] Executing function ==");
+ log->Printf("== [ClangFunction::ExecuteFunction] Executing function \"%s\" ==", m_name.c_str());
lldb::ThreadPlanSP call_plan_sp (GetThreadPlanToCallFunction (exe_ctx,
args_addr,
real_options,
errors));
if (!call_plan_sp)
- return eExecutionSetupError;
+ return lldb::eExpressionSetupError;
- // <rdar://problem/12027563> we need to make sure we record the fact that we are running an expression here
+ // We need to make sure we record the fact that we are running an expression here
// otherwise this fact will fail to be recorded when fetching an Objective-C object description
if (exe_ctx.GetProcessPtr())
exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
@@ -530,13 +560,13 @@ ClangFunction::ExecuteFunction(
if (log)
{
- if (return_value != eExecutionCompleted)
+ if (return_value != lldb::eExpressionCompleted)
{
- log->Printf("== [ClangFunction::ExecuteFunction] Execution completed abnormally ==");
+ log->Printf("== [ClangFunction::ExecuteFunction] Execution of \"%s\" completed abnormally ==", m_name.c_str());
}
else
{
- log->Printf("== [ClangFunction::ExecuteFunction] Execution completed normally ==");
+ log->Printf("== [ClangFunction::ExecuteFunction] Execution of \"%s\" completed normally ==", m_name.c_str());
}
}
@@ -546,7 +576,7 @@ ClangFunction::ExecuteFunction(
if (args_addr_ptr != NULL)
*args_addr_ptr = args_addr;
- if (return_value != eExecutionCompleted)
+ if (return_value != lldb::eExpressionCompleted)
return return_value;
FetchFunctionResults(exe_ctx, args_addr, results);
@@ -554,7 +584,7 @@ ClangFunction::ExecuteFunction(
if (args_addr_ptr == NULL)
DeallocateFunctionResults(exe_ctx, args_addr);
- return eExecutionCompleted;
+ return lldb::eExpressionCompleted;
}
clang::ASTConsumer *
diff --git a/source/Expression/ClangUserExpression.cpp b/source/Expression/ClangUserExpression.cpp
index 6b0eee8cf363..52ef4d310352 100644
--- a/source/Expression/ClangUserExpression.cpp
+++ b/source/Expression/ClangUserExpression.cpp
@@ -7,19 +7,18 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
#include <stdio.h>
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
-// C++ Includes
#include <cstdlib>
#include <string>
#include <map>
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectConstResult.h"
@@ -32,10 +31,12 @@
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Expression/IRInterpreter.h"
#include "lldb/Expression/Materializer.h"
-#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
#include "lldb/Symbol/VariableList.h"
@@ -63,6 +64,11 @@ ClangUserExpression::ClangUserExpression (const char *expr,
m_language (language),
m_transformed_text (),
m_desired_type (desired_type),
+ m_expr_decl_map(),
+ m_execution_unit_sp(),
+ m_materializer_ap(),
+ m_result_synthesizer(),
+ m_jit_module_wp(),
m_enforce_valid_object (true),
m_cplusplus (false),
m_objectivec (false),
@@ -91,6 +97,12 @@ ClangUserExpression::ClangUserExpression (const char *expr,
ClangUserExpression::~ClangUserExpression ()
{
+ if (m_target)
+ {
+ lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock());
+ if (jit_module_sp)
+ m_target->GetImages().Remove(jit_module_sp);
+ }
}
clang::ASTConsumer *
@@ -98,7 +110,7 @@ ClangUserExpression::ASTTransformer (clang::ASTConsumer *passthrough)
{
m_result_synthesizer.reset(new ASTResultSynthesizer(passthrough,
*m_target));
-
+
return m_result_synthesizer.get();
}
@@ -109,16 +121,16 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
if (log)
log->Printf("ClangUserExpression::ScanContext()");
-
+
m_target = exe_ctx.GetTargetPtr();
-
+
if (!(m_allow_cxx || m_allow_objc))
{
if (log)
log->Printf(" [CUE::SC] Settings inhibit C++ and Objective-C");
return;
}
-
+
StackFrame *frame = exe_ctx.GetFramePtr();
if (frame == NULL)
{
@@ -126,19 +138,19 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
log->Printf(" [CUE::SC] Null stack frame");
return;
}
-
+
SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction | lldb::eSymbolContextBlock);
-
+
if (!sym_ctx.function)
{
if (log)
log->Printf(" [CUE::SC] Null function");
return;
}
-
+
// Find the block that defines the function represented by "sym_ctx"
Block *function_block = sym_ctx.GetFunctionBlock();
-
+
if (!function_block)
{
if (log)
@@ -154,7 +166,7 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
log->Printf(" [CUE::SC] Null decl context");
return;
}
-
+
if (clang::CXXMethodDecl *method_decl = llvm::dyn_cast<clang::CXXMethodDecl>(decl_context))
{
if (m_allow_cxx && method_decl->isInstance())
@@ -162,60 +174,60 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
if (m_enforce_valid_object)
{
lldb::VariableListSP variable_list_sp (function_block->GetBlockVariableList (true));
-
+
const char *thisErrorString = "Stopped in a C++ method, but 'this' isn't available; pretending we are in a generic context";
-
+
if (!variable_list_sp)
{
err.SetErrorString(thisErrorString);
return;
}
-
+
lldb::VariableSP this_var_sp (variable_list_sp->FindVariable(ConstString("this")));
-
+
if (!this_var_sp ||
- !this_var_sp->IsInScope(frame) ||
+ !this_var_sp->IsInScope(frame) ||
!this_var_sp->LocationIsValidForFrame (frame))
{
err.SetErrorString(thisErrorString);
return;
}
}
-
+
m_cplusplus = true;
m_needs_object_ptr = true;
}
}
else if (clang::ObjCMethodDecl *method_decl = llvm::dyn_cast<clang::ObjCMethodDecl>(decl_context))
- {
+ {
if (m_allow_objc)
{
if (m_enforce_valid_object)
{
lldb::VariableListSP variable_list_sp (function_block->GetBlockVariableList (true));
-
+
const char *selfErrorString = "Stopped in an Objective-C method, but 'self' isn't available; pretending we are in a generic context";
-
+
if (!variable_list_sp)
{
err.SetErrorString(selfErrorString);
return;
}
-
+
lldb::VariableSP self_variable_sp = variable_list_sp->FindVariable(ConstString("self"));
-
- if (!self_variable_sp ||
- !self_variable_sp->IsInScope(frame) ||
+
+ if (!self_variable_sp ||
+ !self_variable_sp->IsInScope(frame) ||
!self_variable_sp->LocationIsValidForFrame (frame))
{
err.SetErrorString(selfErrorString);
return;
}
}
-
+
m_objectivec = true;
m_needs_object_ptr = true;
-
+
if (!method_decl->isInstanceMethod())
m_static_method = true;
}
@@ -226,7 +238,7 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
// object pointer. The best way to deal with getting to the ivars at present it by pretending
// that this is a method of a class in whatever runtime the debug info says the object pointer
// belongs to. Do that here.
-
+
ClangASTMetadata *metadata = ClangASTContext::GetMetadata (&decl_context->getParentASTContext(), function_decl);
if (metadata && metadata->HasObjectPtr())
{
@@ -236,17 +248,17 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
if (m_enforce_valid_object)
{
lldb::VariableListSP variable_list_sp (function_block->GetBlockVariableList (true));
-
+
const char *thisErrorString = "Stopped in a context claiming to capture a C++ object pointer, but 'this' isn't available; pretending we are in a generic context";
-
+
if (!variable_list_sp)
{
err.SetErrorString(thisErrorString);
return;
}
-
+
lldb::VariableSP this_var_sp (variable_list_sp->FindVariable(ConstString("this")));
-
+
if (!this_var_sp ||
!this_var_sp->IsInScope(frame) ||
!this_var_sp->LocationIsValidForFrame (frame))
@@ -255,7 +267,7 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
return;
}
}
-
+
m_cplusplus = true;
m_needs_object_ptr = true;
}
@@ -264,17 +276,17 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
if (m_enforce_valid_object)
{
lldb::VariableListSP variable_list_sp (function_block->GetBlockVariableList (true));
-
+
const char *selfErrorString = "Stopped in a context claiming to capture an Objective-C object pointer, but 'self' isn't available; pretending we are in a generic context";
-
+
if (!variable_list_sp)
{
err.SetErrorString(selfErrorString);
return;
}
-
+
lldb::VariableSP self_variable_sp = variable_list_sp->FindVariable(ConstString("self"));
-
+
if (!self_variable_sp ||
!self_variable_sp->IsInScope(frame) ||
!self_variable_sp->LocationIsValidForFrame (frame))
@@ -282,23 +294,23 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
err.SetErrorString(selfErrorString);
return;
}
-
+
Type *self_type = self_variable_sp->GetType();
-
+
if (!self_type)
{
err.SetErrorString(selfErrorString);
return;
}
-
+
ClangASTType self_clang_type = self_type->GetClangForwardType();
-
+
if (!self_clang_type)
{
err.SetErrorString(selfErrorString);
return;
}
-
+
if (self_clang_type.IsObjCClassType())
{
return;
@@ -328,9 +340,9 @@ void
ClangUserExpression::InstallContext (ExecutionContext &exe_ctx)
{
m_process_wp = exe_ctx.GetProcessSP();
-
+
lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP();
-
+
if (frame_sp)
m_address = frame_sp->GetFrameCodeAddress();
}
@@ -346,11 +358,11 @@ ClangUserExpression::LockAndCheckContext (ExecutionContext &exe_ctx,
if (process_sp != expected_process_sp)
return false;
-
+
process_sp = exe_ctx.GetProcessSP();
target_sp = exe_ctx.GetTargetSP();
frame_sp = exe_ctx.GetFrameSP();
-
+
if (m_address.IsValid())
{
if (!frame_sp)
@@ -358,7 +370,7 @@ ClangUserExpression::LockAndCheckContext (ExecutionContext &exe_ctx,
else
return (0 == Address::CompareLoadAddress(m_address, frame_sp->GetFrameCodeAddress(), target_sp.get()));
}
-
+
return true;
}
@@ -368,7 +380,7 @@ ClangUserExpression::MatchesContext (ExecutionContext &exe_ctx)
lldb::TargetSP target_sp;
lldb::ProcessSP process_sp;
lldb::StackFrameSP frame_sp;
-
+
return LockAndCheckContext(exe_ctx, target_sp, process_sp, frame_sp);
}
@@ -383,7 +395,7 @@ ApplyObjcCastHack(std::string &expr)
#define OBJC_CAST_HACK_TO "(int)(long long)["
size_t from_offset;
-
+
while ((from_offset = expr.find(OBJC_CAST_HACK_FROM)) != expr.npos)
expr.replace(from_offset, sizeof(OBJC_CAST_HACK_FROM) - 1, OBJC_CAST_HACK_TO);
@@ -396,99 +408,100 @@ ApplyObjcCastHack(std::string &expr)
// hopefully we'll figure out a way to #include the same environment as is
// present in the original source file rather than try to hack specific type
// definitions in as needed.
-static void
-ApplyUnicharHack(std::string &expr)
-{
-#define UNICHAR_HACK_FROM "unichar"
-#define UNICHAR_HACK_TO "unsigned short"
-
- size_t from_offset;
-
- while ((from_offset = expr.find(UNICHAR_HACK_FROM)) != expr.npos)
- expr.replace(from_offset, sizeof(UNICHAR_HACK_FROM) - 1, UNICHAR_HACK_TO);
-
-#undef UNICHAR_HACK_TO
-#undef UNICHAR_HACK_FROM
-}
+//static void
+//ApplyUnicharHack(std::string &expr)
+//{
+//#define UNICHAR_HACK_FROM "unichar"
+//#define UNICHAR_HACK_TO "unsigned short"
+//
+// size_t from_offset;
+//
+// while ((from_offset = expr.find(UNICHAR_HACK_FROM)) != expr.npos)
+// expr.replace(from_offset, sizeof(UNICHAR_HACK_FROM) - 1, UNICHAR_HACK_TO);
+//
+//#undef UNICHAR_HACK_TO
+//#undef UNICHAR_HACK_FROM
+//}
bool
-ClangUserExpression::Parse (Stream &error_stream,
+ClangUserExpression::Parse (Stream &error_stream,
ExecutionContext &exe_ctx,
lldb_private::ExecutionPolicy execution_policy,
- bool keep_result_in_memory)
+ bool keep_result_in_memory,
+ bool generate_debug_info)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
Error err;
-
+
InstallContext(exe_ctx);
-
+
ScanContext(exe_ctx, err);
-
+
if (!err.Success())
{
error_stream.Printf("warning: %s\n", err.AsCString());
}
-
+
StreamString m_transformed_stream;
-
+
////////////////////////////////////
// Generate the expression
//
-
+
ApplyObjcCastHack(m_expr_text);
//ApplyUnicharHack(m_expr_text);
std::unique_ptr<ExpressionSourceCode> source_code (ExpressionSourceCode::CreateWrapped(m_expr_prefix.c_str(), m_expr_text.c_str()));
-
+
lldb::LanguageType lang_type;
-
+
if (m_cplusplus)
lang_type = lldb::eLanguageTypeC_plus_plus;
else if(m_objectivec)
lang_type = lldb::eLanguageTypeObjC;
else
lang_type = lldb::eLanguageTypeC;
-
- if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_static_method))
+
+ if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_static_method, exe_ctx))
{
error_stream.PutCString ("error: couldn't construct expression body");
return false;
}
-
+
if (log)
log->Printf("Parsing the following code:\n%s", m_transformed_text.c_str());
-
+
////////////////////////////////////
// Set up the target and compiler
//
-
+
Target *target = exe_ctx.GetTargetPtr();
-
+
if (!target)
{
error_stream.PutCString ("error: invalid target\n");
return false;
}
-
+
//////////////////////////
// Parse the expression
//
-
+
m_materializer_ap.reset(new Materializer());
-
+
m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx));
-
+
class OnExit
{
public:
typedef std::function <void (void)> Callback;
-
+
OnExit (Callback const &callback) :
m_callback(callback)
{
}
-
+
~OnExit ()
{
m_callback();
@@ -496,50 +509,81 @@ ClangUserExpression::Parse (Stream &error_stream,
private:
Callback m_callback;
};
-
+
OnExit on_exit([this]() { m_expr_decl_map.reset(); });
-
+
if (!m_expr_decl_map->WillParse(exe_ctx, m_materializer_ap.get()))
{
error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n");
-
+
m_expr_decl_map.reset(); // We are being careful here in the case of breakpoint conditions.
-
+
return false;
}
-
+
Process *process = exe_ctx.GetProcessPtr();
ExecutionContextScope *exe_scope = process;
-
+
if (!exe_scope)
exe_scope = exe_ctx.GetTargetPtr();
-
- ClangExpressionParser parser(exe_scope, *this);
-
+
+ ClangExpressionParser parser(exe_scope, *this, generate_debug_info);
+
unsigned num_errors = parser.Parse (error_stream);
-
+
if (num_errors)
{
error_stream.Printf ("error: %d errors parsing expression\n", num_errors);
-
+
m_expr_decl_map.reset(); // We are being careful here in the case of breakpoint conditions.
-
+
return false;
}
-
+
//////////////////////////////////////////////////////////////////////////////////////////
// Prepare the output of the parser for execution, evaluating it statically if possible
//
-
+
Error jit_error = parser.PrepareForExecution (m_jit_start_addr,
m_jit_end_addr,
- m_execution_unit_ap,
+ m_execution_unit_sp,
exe_ctx,
m_can_interpret,
execution_policy);
-
+
+ if (generate_debug_info)
+ {
+ lldb::ModuleSP jit_module_sp ( m_execution_unit_sp->GetJITModule());
+
+ if (jit_module_sp)
+ {
+ ConstString const_func_name(FunctionName());
+ FileSpec jit_file;
+ jit_file.GetFilename() = const_func_name;
+ jit_module_sp->SetFileSpecAndObjectName (jit_file, ConstString());
+ m_jit_module_wp = jit_module_sp;
+ target->GetImages().Append(jit_module_sp);
+ }
+// lldb_private::ObjectFile *jit_obj_file = jit_module_sp->GetObjectFile();
+// StreamFile strm (stdout, false);
+// if (jit_obj_file)
+// {
+// jit_obj_file->GetSectionList();
+// jit_obj_file->GetSymtab();
+// jit_obj_file->Dump(&strm);
+// }
+// lldb_private::SymbolVendor *jit_sym_vendor = jit_module_sp->GetSymbolVendor();
+// if (jit_sym_vendor)
+// {
+// lldb_private::SymbolContextList sc_list;
+// jit_sym_vendor->FindFunctions(const_func_name, NULL, lldb::eFunctionNameTypeFull, true, false, sc_list);
+// sc_list.Dump(&strm, target);
+// jit_sym_vendor->Dump(&strm);
+// }
+ }
+
m_expr_decl_map.reset(); // Make this go away since we don't need any of its state after parsing. This also gets rid of any ClangASTImporter::Minions.
-
+
if (jit_error.Success())
{
if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS)
@@ -563,16 +607,16 @@ GetObjectPointer (lldb::StackFrameSP frame_sp,
Error &err)
{
err.Clear();
-
+
if (!frame_sp)
{
err.SetErrorStringWithFormat("Couldn't load '%s' because the context is incomplete", object_name.AsCString());
return LLDB_INVALID_ADDRESS;
}
-
+
lldb::VariableSP var_sp;
lldb::ValueObjectSP valobj_sp;
-
+
valobj_sp = frame_sp->GetValueForVariableExpressionPath(object_name.AsCString(),
lldb::eNoDynamicValues,
StackFrame::eExpressionPathOptionCheckPtrVsMember ||
@@ -582,18 +626,18 @@ GetObjectPointer (lldb::StackFrameSP frame_sp,
StackFrame::eExpressionPathOptionsNoSyntheticArrayRange,
var_sp,
err);
-
+
if (!err.Success())
return LLDB_INVALID_ADDRESS;
-
+
lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
-
+
if (ret == LLDB_INVALID_ADDRESS)
{
err.SetErrorStringWithFormat("Couldn't load '%s' because its value couldn't be evaluated", object_name.AsCString());
return LLDB_INVALID_ADDRESS;
}
-
+
return ret;
}
@@ -607,22 +651,22 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
lldb::TargetSP target;
lldb::ProcessSP process;
lldb::StackFrameSP frame;
-
+
if (!LockAndCheckContext(exe_ctx,
target,
- process,
+ process,
frame))
{
error_stream.Printf("The context has changed before we could JIT the expression!\n");
return false;
}
-
+
if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret)
- {
+ {
if (m_needs_object_ptr)
{
ConstString object_name;
-
+
if (m_cplusplus)
{
object_name.SetCString("this");
@@ -636,23 +680,23 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
error_stream.Printf("Need object pointer but don't know the language\n");
return false;
}
-
+
Error object_ptr_error;
-
+
object_ptr = GetObjectPointer(frame, object_name, object_ptr_error);
-
+
if (!object_ptr_error.Success())
{
error_stream.Printf("warning: couldn't get required object pointer (substituting NULL): %s\n", object_ptr_error.AsCString());
object_ptr = 0;
}
-
+
if (m_objectivec)
{
ConstString cmd_name("_cmd");
-
+
cmd_ptr = GetObjectPointer(frame, cmd_name, object_ptr_error);
-
+
if (!object_ptr_error.Success())
{
error_stream.Printf("warning: couldn't get cmd pointer (substituting NULL): %s\n", object_ptr_error.AsCString());
@@ -660,56 +704,56 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
}
}
}
-
+
if (m_materialized_address == LLDB_INVALID_ADDRESS)
{
Error alloc_error;
-
+
IRMemoryMap::AllocationPolicy policy = m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly : IRMemoryMap::eAllocationPolicyMirror;
-
- m_materialized_address = m_execution_unit_ap->Malloc(m_materializer_ap->GetStructByteSize(),
+
+ m_materialized_address = m_execution_unit_sp->Malloc(m_materializer_ap->GetStructByteSize(),
m_materializer_ap->GetStructAlignment(),
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
policy,
alloc_error);
-
+
if (!alloc_error.Success())
{
error_stream.Printf("Couldn't allocate space for materialized struct: %s\n", alloc_error.AsCString());
return false;
}
}
-
+
struct_address = m_materialized_address;
-
+
if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS)
{
Error alloc_error;
const size_t stack_frame_size = 512 * 1024;
-
- m_stack_frame_bottom = m_execution_unit_ap->Malloc(stack_frame_size,
+
+ m_stack_frame_bottom = m_execution_unit_sp->Malloc(stack_frame_size,
8,
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
IRMemoryMap::eAllocationPolicyHostOnly,
alloc_error);
-
+
m_stack_frame_top = m_stack_frame_bottom + stack_frame_size;
-
+
if (!alloc_error.Success())
{
error_stream.Printf("Couldn't allocate space for the stack frame: %s\n", alloc_error.AsCString());
return false;
}
}
-
+
Error materialize_error;
-
- m_dematerializer_sp = m_materializer_ap->Materialize(frame, *m_execution_unit_ap, struct_address, materialize_error);
-
+
+ m_dematerializer_sp = m_materializer_ap->Materialize(frame, *m_execution_unit_sp, struct_address, materialize_error);
+
if (!materialize_error.Success())
{
- error_stream.Printf("Couldn't materialize struct: %s\n", materialize_error.AsCString());
+ error_stream.Printf("Couldn't materialize: %s\n", materialize_error.AsCString());
return false;
}
}
@@ -724,18 +768,18 @@ ClangUserExpression::FinalizeJITExecution (Stream &error_stream,
lldb::addr_t function_stack_top)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (log)
log->Printf("-- [ClangUserExpression::FinalizeJITExecution] Dematerializing after execution --");
-
+
if (!m_dematerializer_sp)
{
error_stream.Printf ("Couldn't apply expression side effects : no dematerializer is present");
return false;
}
-
+
Error dematerialize_error;
-
+
m_dematerializer_sp->Dematerialize(dematerialize_error, result, function_stack_bottom, function_stack_top);
if (!dematerialize_error.Success())
@@ -743,16 +787,16 @@ ClangUserExpression::FinalizeJITExecution (Stream &error_stream,
error_stream.Printf ("Couldn't apply expression side effects : %s\n", dematerialize_error.AsCString("unknown error"));
return false;
}
-
+
if (result)
result->TransferAddress();
-
+
m_dematerializer_sp.reset();
-
+
return true;
-}
+}
-ExecutionResults
+lldb::ExpressionResults
ClangUserExpression::Execute (Stream &error_stream,
ExecutionContext &exe_ctx,
const EvaluateExpressionOptions& options,
@@ -766,110 +810,118 @@ ClangUserExpression::Execute (Stream &error_stream,
if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret)
{
lldb::addr_t struct_address = LLDB_INVALID_ADDRESS;
-
+
lldb::addr_t object_ptr = 0;
lldb::addr_t cmd_ptr = 0;
-
+
if (!PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr, cmd_ptr))
{
error_stream.Printf("Errored out in %s, couldn't PrepareToExecuteJITExpression", __FUNCTION__);
- return eExecutionSetupError;
+ return lldb::eExpressionSetupError;
}
-
+
lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS;
lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS;
-
+
if (m_can_interpret)
- {
- llvm::Module *module = m_execution_unit_ap->GetModule();
- llvm::Function *function = m_execution_unit_ap->GetFunction();
-
+ {
+ llvm::Module *module = m_execution_unit_sp->GetModule();
+ llvm::Function *function = m_execution_unit_sp->GetFunction();
+
if (!module || !function)
{
error_stream.Printf("Supposed to interpret, but nothing is there");
- return eExecutionSetupError;
+ return lldb::eExpressionSetupError;
}
Error interpreter_error;
-
+
llvm::SmallVector <lldb::addr_t, 3> args;
-
+
if (m_needs_object_ptr)
{
args.push_back(object_ptr);
-
+
if (m_objectivec)
args.push_back(cmd_ptr);
}
-
+
args.push_back(struct_address);
-
+
function_stack_bottom = m_stack_frame_bottom;
function_stack_top = m_stack_frame_top;
-
+
IRInterpreter::Interpret (*module,
*function,
args,
- *m_execution_unit_ap.get(),
+ *m_execution_unit_sp.get(),
interpreter_error,
function_stack_bottom,
function_stack_top);
-
+
if (!interpreter_error.Success())
{
error_stream.Printf("Supposed to interpret, but failed: %s", interpreter_error.AsCString());
- return eExecutionDiscarded;
+ return lldb::eExpressionDiscarded;
}
}
else
{
+ if (!exe_ctx.HasThreadScope())
+ {
+ error_stream.Printf("ClangUserExpression::Execute called with no thread selected.");
+ return lldb::eExpressionSetupError;
+ }
+
Address wrapper_address (m_jit_start_addr);
-
+
llvm::SmallVector <lldb::addr_t, 3> args;
-
+
if (m_needs_object_ptr) {
args.push_back(object_ptr);
if (m_objectivec)
args.push_back(cmd_ptr);
}
-
+
args.push_back(struct_address);
-
- lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),
- wrapper_address,
- args,
- options,
- shared_ptr_to_me));
-
+
+ ThreadPlanCallUserExpression *user_expression_plan =
+ new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),
+ wrapper_address,
+ args,
+ options,
+ shared_ptr_to_me);
+ lldb::ThreadPlanSP call_plan_sp(user_expression_plan);
+
if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream))
- return eExecutionSetupError;
-
- lldb::addr_t function_stack_pointer = static_cast<ThreadPlanCallFunction *>(call_plan_sp.get())->GetFunctionStackPointer();
+ return lldb::eExpressionSetupError;
- function_stack_bottom = function_stack_pointer - Host::GetPageSize();
+ lldb::addr_t function_stack_pointer = user_expression_plan->GetFunctionStackPointer();
+
+ function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize();
function_stack_top = function_stack_pointer;
-
+
if (log)
log->Printf("-- [ClangUserExpression::Execute] Execution of expression begins --");
-
+
if (exe_ctx.GetProcessPtr())
exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
-
- ExecutionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx,
+
+ lldb::ExpressionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx,
call_plan_sp,
options,
error_stream);
-
+
if (exe_ctx.GetProcessPtr())
exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
-
+
if (log)
log->Printf("-- [ClangUserExpression::Execute] Execution of expression completed --");
- if (execution_result == eExecutionInterrupted || execution_result == eExecutionHitBreakpoint)
+ if (execution_result == lldb::eExpressionInterrupted || execution_result == lldb::eExpressionHitBreakpoint)
{
const char *error_desc = NULL;
-
+
if (call_plan_sp)
{
lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo();
@@ -880,45 +932,51 @@ ClangUserExpression::Execute (Stream &error_stream,
error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc);
else
error_stream.PutCString ("Execution was interrupted.");
-
- if ((execution_result == eExecutionInterrupted && options.DoesUnwindOnError())
- || (execution_result == eExecutionHitBreakpoint && options.DoesIgnoreBreakpoints()))
+
+ if ((execution_result == lldb::eExpressionInterrupted && options.DoesUnwindOnError())
+ || (execution_result == lldb::eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints()))
error_stream.PutCString ("\nThe process has been returned to the state before expression evaluation.");
else
- error_stream.PutCString ("\nThe process has been left at the point where it was interrupted, use \"thread return -x\" to return to the state before expression evaluation.");
+ {
+ if (execution_result == lldb::eExpressionHitBreakpoint)
+ user_expression_plan->TransferExpressionOwnership();
+ error_stream.PutCString ("\nThe process has been left at the point where it was interrupted, "
+ "use \"thread return -x\" to return to the state before expression evaluation.");
+ }
return execution_result;
}
- else if (execution_result == eExecutionStoppedForDebug)
+ else if (execution_result == lldb::eExpressionStoppedForDebug)
{
- error_stream.PutCString ("Execution was halted at the first instruction of the expression function because \"debug\" was requested.\n"
+ error_stream.PutCString ("Execution was halted at the first instruction of the expression "
+ "function because \"debug\" was requested.\n"
"Use \"thread return -x\" to return to the state before expression evaluation.");
return execution_result;
}
- else if (execution_result != eExecutionCompleted)
+ else if (execution_result != lldb::eExpressionCompleted)
{
error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result));
return execution_result;
}
}
-
+
if (FinalizeJITExecution (error_stream, exe_ctx, result, function_stack_bottom, function_stack_top))
{
- return eExecutionCompleted;
+ return lldb::eExpressionCompleted;
}
else
{
- return eExecutionSetupError;
+ return lldb::eExpressionResultUnavailable;
}
}
else
{
error_stream.Printf("Expression can't be run, because there is no JIT compiled function");
- return eExecutionSetupError;
+ return lldb::eExpressionSetupError;
}
}
-ExecutionResults
+lldb::ExpressionResults
ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
const EvaluateExpressionOptions& options,
const char *expr_cstr,
@@ -931,8 +989,8 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy();
const lldb::LanguageType language = options.GetLanguage();
const ResultType desired_type = options.DoesCoerceToId() ? ClangUserExpression::eResultTypeId : ClangUserExpression::eResultTypeAny;
- ExecutionResults execution_results = eExecutionSetupError;
-
+ lldb::ExpressionResults execution_results = lldb::eExpressionSetupError;
+
Process *process = exe_ctx.GetProcessPtr();
if (process == NULL || process->GetState() != lldb::eStateStopped)
@@ -941,31 +999,43 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
{
if (log)
log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant ==");
-
+
error.SetErrorString ("expression needed to run but couldn't");
-
+
return execution_results;
}
}
-
+
if (process == NULL || !process->CanJIT())
execution_policy = eExecutionPolicyNever;
-
+
ClangUserExpressionSP user_expression_sp (new ClangUserExpression (expr_cstr, expr_prefix, language, desired_type));
StreamString error_stream;
-
+
if (log)
log->Printf("== [ClangUserExpression::Evaluate] Parsing expression %s ==", expr_cstr);
-
+
const bool keep_expression_in_memory = true;
-
- if (!user_expression_sp->Parse (error_stream, exe_ctx, execution_policy, keep_expression_in_memory))
+ const bool generate_debug_info = options.GetGenerateDebugInfo();
+
+ if (options.InvokeCancelCallback (lldb::eExpressionEvaluationParse))
+ {
+ error.SetErrorString ("expression interrupted by callback before parse");
+ result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error);
+ return lldb::eExpressionInterrupted;
+ }
+
+ if (!user_expression_sp->Parse (error_stream,
+ exe_ctx,
+ execution_policy,
+ keep_expression_in_memory,
+ generate_debug_info))
{
if (error_stream.GetString().empty())
- error.SetErrorString ("expression failed to parse, unknown error");
+ error.SetExpressionError (lldb::eExpressionParseError, "expression failed to parse, unknown error");
else
- error.SetErrorString (error_stream.GetString().c_str());
+ error.SetExpressionError (lldb::eExpressionParseError, error_stream.GetString().c_str());
}
else
{
@@ -976,53 +1046,72 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
{
if (log)
log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant ==");
-
+
if (error_stream.GetString().empty())
- error.SetErrorString ("expression needed to run but couldn't");
+ error.SetExpressionError (lldb::eExpressionSetupError, "expression needed to run but couldn't");
}
else
- {
+ {
+ if (options.InvokeCancelCallback (lldb::eExpressionEvaluationExecution))
+ {
+ error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback before execution");
+ result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error);
+ return lldb::eExpressionInterrupted;
+ }
+
error_stream.GetString().clear();
-
+
if (log)
log->Printf("== [ClangUserExpression::Evaluate] Executing expression ==");
- execution_results = user_expression_sp->Execute (error_stream,
+ execution_results = user_expression_sp->Execute (error_stream,
exe_ctx,
options,
user_expression_sp,
expr_result);
-
- if (execution_results != eExecutionCompleted)
+
+ if (options.GetResultIsInternal())
+ {
+ process->GetTarget().GetPersistentVariables().RemovePersistentVariable (expr_result);
+ }
+
+ if (execution_results != lldb::eExpressionCompleted)
{
if (log)
log->Printf("== [ClangUserExpression::Evaluate] Execution completed abnormally ==");
-
+
if (error_stream.GetString().empty())
- error.SetErrorString ("expression failed to execute, unknown error");
+ error.SetExpressionError (execution_results, "expression failed to execute, unknown error");
else
- error.SetErrorString (error_stream.GetString().c_str());
+ error.SetExpressionError (execution_results, error_stream.GetString().c_str());
}
- else
+ else
{
if (expr_result)
{
result_valobj_sp = expr_result->GetValueObject();
-
+
if (log)
- log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with result %s ==", result_valobj_sp->GetValueAsCString());
+ log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with result %s ==",
+ result_valobj_sp->GetValueAsCString());
}
else
{
if (log)
log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with no result ==");
-
+
error.SetError(ClangUserExpression::kNoResult, lldb::eErrorTypeGeneric);
}
}
}
}
-
+
+ if (options.InvokeCancelCallback(lldb::eExpressionEvaluationComplete))
+ {
+ error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback after complete");
+ return lldb::eExpressionInterrupted;
+ }
+
if (result_valobj_sp.get() == NULL)
{
result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error);
diff --git a/source/Expression/ClangUtilityFunction.cpp b/source/Expression/ClangUtilityFunction.cpp
index c911c279993f..de5b0c1b03f4 100644
--- a/source/Expression/ClangUtilityFunction.cpp
+++ b/source/Expression/ClangUtilityFunction.cpp
@@ -17,6 +17,7 @@
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Expression/ClangExpressionDeclMap.h"
@@ -42,6 +43,9 @@ using namespace lldb_private;
ClangUtilityFunction::ClangUtilityFunction (const char *text,
const char *name) :
ClangExpression (),
+ m_expr_decl_map (),
+ m_execution_unit_sp (),
+ m_jit_module_wp (),
m_function_text (ExpressionSourceCode::g_expression_prefix),
m_function_name (name)
{
@@ -51,6 +55,14 @@ ClangUtilityFunction::ClangUtilityFunction (const char *text,
ClangUtilityFunction::~ClangUtilityFunction ()
{
+ lldb::ProcessSP process_sp (m_jit_process_wp.lock());
+ if (process_sp)
+ {
+ lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock());
+ if (jit_module_sp)
+ process_sp->GetTarget().GetImages().Remove(jit_module_sp);
+ }
+
}
//------------------------------------------------------------------
@@ -108,8 +120,9 @@ ClangUtilityFunction::Install (Stream &error_stream,
error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n");
return false;
}
-
- ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this);
+
+ const bool generate_debug_info = true;
+ ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this, generate_debug_info);
unsigned num_errors = parser.Parse (error_stream);
@@ -130,13 +143,29 @@ ClangUtilityFunction::Install (Stream &error_stream,
Error jit_error = parser.PrepareForExecution (m_jit_start_addr,
m_jit_end_addr,
- m_execution_unit_ap,
+ m_execution_unit_sp,
exe_ctx,
can_interpret,
eExecutionPolicyAlways);
if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
- m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
+ {
+ m_jit_process_wp = process->shared_from_this();
+ if (parser.GetGenerateDebugInfo())
+ {
+ lldb::ModuleSP jit_module_sp ( m_execution_unit_sp->GetJITModule());
+
+ if (jit_module_sp)
+ {
+ ConstString const_func_name(FunctionName());
+ FileSpec jit_file;
+ jit_file.GetFilename() = const_func_name;
+ jit_module_sp->SetFileSpecAndObjectName (jit_file, ConstString());
+ m_jit_module_wp = jit_module_sp;
+ target->GetImages().Append(jit_module_sp);
+ }
+ }
+ }
#if 0
// jingham: look here
diff --git a/source/Expression/DWARFExpression.cpp b/source/Expression/DWARFExpression.cpp
index 28aa6d02a56d..44b64ab1bf29 100644
--- a/source/Expression/DWARFExpression.cpp
+++ b/source/Expression/DWARFExpression.cpp
@@ -282,6 +282,33 @@ DWARFExpression::CopyOpcodeData (lldb::ModuleSP module_sp, const DataExtractor&
}
void
+DWARFExpression::CopyOpcodeData (const void *data,
+ lldb::offset_t data_length,
+ ByteOrder byte_order,
+ uint8_t addr_byte_size)
+{
+ if (data && data_length)
+ {
+ m_data.SetData(DataBufferSP(new DataBufferHeap(data, data_length)));
+ m_data.SetByteOrder(byte_order);
+ m_data.SetAddressByteSize(addr_byte_size);
+ }
+}
+
+void
+DWARFExpression::CopyOpcodeData (uint64_t const_value,
+ lldb::offset_t const_value_byte_size,
+ uint8_t addr_byte_size)
+{
+ if (const_value_byte_size)
+ {
+ m_data.SetData(DataBufferSP(new DataBufferHeap(&const_value, const_value_byte_size)));
+ m_data.SetByteOrder(endian::InlHostByteOrder());
+ m_data.SetAddressByteSize(addr_byte_size);
+ }
+}
+
+void
DWARFExpression::SetOpcodeData (lldb::ModuleSP module_sp, const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length)
{
m_module_wp = module_sp;
@@ -728,7 +755,7 @@ static bool
ReadRegisterValueAsScalar
(
RegisterContext *reg_ctx,
- uint32_t reg_kind,
+ lldb::RegisterKind reg_kind,
uint32_t reg_num,
Error *error_ptr,
Value &value
@@ -1307,11 +1334,11 @@ DWARFExpression::Evaluate
ClangExpressionVariableList *expr_locals,
ClangExpressionDeclMap *decl_map,
RegisterContext *reg_ctx,
- lldb::ModuleSP opcode_ctx,
+ lldb::ModuleSP module_sp,
const DataExtractor& opcodes,
const lldb::offset_t opcodes_offset,
const lldb::offset_t opcodes_length,
- const uint32_t reg_kind,
+ const lldb::RegisterKind reg_kind,
const Value* initial_value_ptr,
Value& result,
Error *error_ptr
@@ -1345,6 +1372,10 @@ DWARFExpression::Evaluate
Value tmp;
uint32_t reg_num;
+ /// Insertion point for evaluating multi-piece expression.
+ uint64_t op_piece_offset = 0;
+ Value pieces; // Used for DW_OP_piece
+
// Make sure all of the data is available in opcodes.
if (!opcodes.ValidOffsetForDataOfSize(opcodes_offset, opcodes_length))
{
@@ -1363,7 +1394,7 @@ DWARFExpression::Evaluate
if (log && log->GetVerbose())
{
size_t count = stack.size();
- log->Printf("Stack before operation has %zu values:", count);
+ log->Printf("Stack before operation has %" PRIu64 " values:", (uint64_t)count);
for (size_t i=0; i<count; ++i)
{
StreamString new_value;
@@ -1453,14 +1484,11 @@ DWARFExpression::Evaluate
if (process)
{
lldb::addr_t pointer_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
- uint8_t addr_bytes[sizeof(lldb::addr_t)];
- uint32_t addr_size = process->GetAddressByteSize();
Error error;
- if (process->ReadMemory(pointer_addr, &addr_bytes, addr_size, error) == addr_size)
+ lldb::addr_t pointer_value = process->ReadPointerFromMemory(pointer_addr, error);
+ if (pointer_value != LLDB_INVALID_ADDRESS)
{
- DataExtractor addr_data(addr_bytes, sizeof(addr_bytes), process->GetByteOrder(), addr_size);
- lldb::offset_t addr_data_offset = 0;
- stack.back().GetScalar() = addr_data.GetPointer(&addr_data_offset);
+ stack.back().GetScalar() = pointer_value;
stack.back().ClearContext();
}
else
@@ -2574,45 +2602,134 @@ DWARFExpression::Evaluate
// variable a particular DWARF expression refers to.
//----------------------------------------------------------------------
case DW_OP_piece:
- if (stack.size() < 1)
- {
- if (error_ptr)
- error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_piece.");
- return false;
- }
- else
{
const uint64_t piece_byte_size = opcodes.GetULEB128(&offset);
- switch (stack.back().GetValueType())
+
+ if (piece_byte_size > 0)
{
- case Value::eValueTypeScalar:
- case Value::eValueTypeFileAddress:
- case Value::eValueTypeLoadAddress:
- case Value::eValueTypeHostAddress:
+ Value curr_piece;
+
+ if (stack.empty())
+ {
+ // In a multi-piece expression, this means that the current piece is not available.
+ // Fill with zeros for now by resizing the data and appending it
+ curr_piece.ResizeData(piece_byte_size);
+ ::memset (curr_piece.GetBuffer().GetBytes(), 0, piece_byte_size);
+ pieces.AppendDataToHostBuffer(curr_piece);
+ }
+ else
+ {
+ Error error;
+ // Extract the current piece into "curr_piece"
+ Value curr_piece_source_value(stack.back());
+ stack.pop_back();
+
+ const Value::ValueType curr_piece_source_value_type = curr_piece_source_value.GetValueType();
+ switch (curr_piece_source_value_type)
{
- uint32_t bit_size = piece_byte_size * 8;
- uint32_t bit_offset = 0;
- if (!stack.back().GetScalar().ExtractBitfield (bit_size, bit_offset))
+ case Value::eValueTypeLoadAddress:
+ if (process)
+ {
+ if (curr_piece.ResizeData(piece_byte_size) == piece_byte_size)
+ {
+ lldb::addr_t load_addr = curr_piece_source_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ if (process->ReadMemory(load_addr, curr_piece.GetBuffer().GetBytes(), piece_byte_size, error) != piece_byte_size)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("failed to read memory DW_OP_piece(%" PRIu64 ") from 0x%" PRIx64,
+ piece_byte_size,
+ load_addr);
+ return false;
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("failed to resize the piece memory buffer for DW_OP_piece(%" PRIu64 ")", piece_byte_size);
+ return false;
+ }
+ }
+ break;
+
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeHostAddress:
+ if (error_ptr)
+ {
+ lldb::addr_t addr = curr_piece_source_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ error_ptr->SetErrorStringWithFormat ("failed to read memory DW_OP_piece(%" PRIu64 ") from %s address 0x%" PRIx64,
+ piece_byte_size,
+ curr_piece_source_value.GetValueType() == Value::eValueTypeFileAddress ? "file" : "host",
+ addr);
+ }
+ return false;
+
+ case Value::eValueTypeScalar:
+ {
+ uint32_t bit_size = piece_byte_size * 8;
+ uint32_t bit_offset = 0;
+ if (!curr_piece_source_value.GetScalar().ExtractBitfield (bit_size, bit_offset))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("unable to extract %" PRIu64 " bytes from a %" PRIu64 " byte scalar value.", piece_byte_size, (uint64_t)curr_piece_source_value.GetScalar().GetByteSize());
+ return false;
+ }
+ curr_piece = curr_piece_source_value;
+ }
+ break;
+
+ case Value::eValueTypeVector:
+ {
+ if (curr_piece_source_value.GetVector().length >= piece_byte_size)
+ curr_piece_source_value.GetVector().length = piece_byte_size;
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("unable to extract %" PRIu64 " bytes from a %" PRIu64 " byte vector value.", piece_byte_size, (uint64_t)curr_piece_source_value.GetVector().length);
+ return false;
+ }
+ }
+ break;
+
+ default:
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("unhandled value type for DW_OP_piece(%" PRIu64 ")", piece_byte_size);
+ return false;
+
+ }
+
+ // Check if this is the first piece?
+ if (op_piece_offset == 0)
+ {
+ // This is the first piece, we should push it back onto the stack so subsequent
+ // pieces will be able to access this piece and add to it
+ if (pieces.AppendDataToHostBuffer(curr_piece) == 0)
{
if (error_ptr)
- error_ptr->SetErrorStringWithFormat("unable to extract %" PRIu64 " bytes from a %" PRIu64 " byte scalar value.", piece_byte_size, (uint64_t)stack.back().GetScalar().GetByteSize());
+ error_ptr->SetErrorString("failed to append piece data");
return false;
}
}
- break;
-
- case Value::eValueTypeVector:
+ else if (!stack.empty())
{
- if (stack.back().GetVector().length >= piece_byte_size)
- stack.back().GetVector().length = piece_byte_size;
- else
+ // If this is the second or later piece there should be a value on the stack
+ if (pieces.GetBuffer().GetByteSize() != op_piece_offset)
{
if (error_ptr)
- error_ptr->SetErrorStringWithFormat("unable to extract %" PRIu64 " bytes from a %" PRIu64 " byte vector value.", piece_byte_size, (uint64_t)stack.back().GetVector().length);
+ error_ptr->SetErrorStringWithFormat ("DW_OP_piece for offset %" PRIu64 " but top of stack is of size %" PRIu64,
+ op_piece_offset,
+ pieces.GetBuffer().GetByteSize());
+ return false;
+ }
+
+ if (pieces.AppendDataToHostBuffer(curr_piece) == 0)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("failed to append piece data");
return false;
}
}
- break;
+ op_piece_offset += piece_byte_size;
+ }
}
}
break;
@@ -2631,9 +2748,6 @@ DWARFExpression::Evaluate
switch (stack.back().GetValueType())
{
case Value::eValueTypeScalar:
- case Value::eValueTypeFileAddress:
- case Value::eValueTypeLoadAddress:
- case Value::eValueTypeHostAddress:
{
if (!stack.back().GetScalar().ExtractBitfield (piece_bit_size, piece_bit_offset))
{
@@ -2646,11 +2760,22 @@ DWARFExpression::Evaluate
}
}
break;
-
+
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeHostAddress:
+ if (error_ptr)
+ {
+ error_ptr->SetErrorStringWithFormat ("unable to extract DW_OP_bit_piece(bit_size = %" PRIu64 ", bit_offset = %" PRIu64 ") from an addresss value.",
+ piece_bit_size,
+ piece_bit_offset);
+ }
+ return false;
+
case Value::eValueTypeVector:
if (error_ptr)
{
- error_ptr->SetErrorStringWithFormat ("unable to extract %" PRIu64 " bit value with %" PRIu64 " bit offset from a vector value.",
+ error_ptr->SetErrorStringWithFormat ("unable to extract DW_OP_bit_piece(bit_size = %" PRIu64 ", bit_offset = %" PRIu64 ") from a vector value.",
piece_bit_size,
piece_bit_offset);
}
@@ -2784,7 +2909,7 @@ DWARFExpression::Evaluate
return false;
}
- if (!exe_ctx || !opcode_ctx)
+ if (!exe_ctx || !module_sp)
{
if (error_ptr)
error_ptr->SetErrorString("No context to evaluate TLS within.");
@@ -2800,7 +2925,7 @@ DWARFExpression::Evaluate
}
// Lookup the TLS block address for this thread and module.
- addr_t tls_addr = thread->GetThreadLocalData (opcode_ctx);
+ addr_t tls_addr = thread->GetThreadLocalData (module_sp);
if (tls_addr == LLDB_INVALID_ADDRESS)
{
@@ -2825,24 +2950,34 @@ DWARFExpression::Evaluate
if (stack.empty())
{
- if (error_ptr)
- error_ptr->SetErrorString ("Stack empty after evaluation.");
- return false;
+ // Nothing on the stack, check if we created a piece value from DW_OP_piece or DW_OP_bit_piece opcodes
+ if (pieces.GetBuffer().GetByteSize())
+ {
+ result = pieces;
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("Stack empty after evaluation.");
+ return false;
+ }
}
- else if (log && log->GetVerbose())
+ else
{
- size_t count = stack.size();
- log->Printf("Stack after operation has %zu values:", count);
- for (size_t i=0; i<count; ++i)
+ if (log && log->GetVerbose())
{
- StreamString new_value;
- new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
- stack[i].Dump(&new_value);
- log->Printf(" %s", new_value.GetData());
+ size_t count = stack.size();
+ log->Printf("Stack after operation has %" PRIu64 " values:", (uint64_t)count);
+ for (size_t i=0; i<count; ++i)
+ {
+ StreamString new_value;
+ new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
+ stack[i].Dump(&new_value);
+ log->Printf(" %s", new_value.GetData());
+ }
}
+ result = stack.back();
}
-
- result = stack.back();
return true; // Return true on success
}
diff --git a/source/Expression/ExpressionSourceCode.cpp b/source/Expression/ExpressionSourceCode.cpp
index aef3b9e301e5..080562e51e91 100644
--- a/source/Expression/ExpressionSourceCode.cpp
+++ b/source/Expression/ExpressionSourceCode.cpp
@@ -10,6 +10,9 @@
#include "lldb/Expression/ExpressionSourceCode.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Target.h"
using namespace lldb_private;
@@ -25,25 +28,45 @@ ExpressionSourceCode::g_expression_prefix = R"(
#define nil (__null)
#define YES ((BOOL)1)
#define NO ((BOOL)0)
-typedef signed char BOOL;
-typedef signed __INT8_TYPE__ int8_t;
-typedef unsigned __INT8_TYPE__ uint8_t;
-typedef signed __INT16_TYPE__ int16_t;
-typedef unsigned __INT16_TYPE__ uint16_t;
-typedef signed __INT32_TYPE__ int32_t;
-typedef unsigned __INT32_TYPE__ uint32_t;
-typedef signed __INT64_TYPE__ int64_t;
-typedef unsigned __INT64_TYPE__ uint64_t;
-typedef signed __INTPTR_TYPE__ intptr_t;
-typedef unsigned __INTPTR_TYPE__ uintptr_t;
+typedef __INT8_TYPE__ int8_t;
+typedef __UINT8_TYPE__ uint8_t;
+typedef __INT16_TYPE__ int16_t;
+typedef __UINT16_TYPE__ uint16_t;
+typedef __INT32_TYPE__ int32_t;
+typedef __UINT32_TYPE__ uint32_t;
+typedef __INT64_TYPE__ int64_t;
+typedef __UINT64_TYPE__ uint64_t;
+typedef __INTPTR_TYPE__ intptr_t;
+typedef __UINTPTR_TYPE__ uintptr_t;
typedef __SIZE_TYPE__ size_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef unsigned short unichar;
)";
-bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, bool static_method) const
+bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, bool static_method, ExecutionContext &exe_ctx) const
{
+ const char *target_specific_defines = "typedef signed char BOOL;\n";
+ static ConstString g_platform_ios_simulator ("PlatformiOSSimulator");
+
+ if (Target *target = exe_ctx.GetTargetPtr())
+ {
+ if (target->GetArchitecture().GetMachine() == llvm::Triple::aarch64)
+ {
+ target_specific_defines = "typedef bool BOOL;\n";
+ }
+ if (target->GetArchitecture().GetMachine() == llvm::Triple::x86_64)
+ {
+ if (lldb::PlatformSP platform_sp = target->GetPlatform())
+ {
+ if (platform_sp->GetPluginName() == g_platform_ios_simulator)
+ {
+ target_specific_defines = "typedef bool BOOL;\n";
+ }
+ }
+ }
+ }
+
if (m_wrap)
{
switch (wrapping_language)
@@ -65,12 +88,14 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
case lldb::eLanguageTypeC:
wrap_stream.Printf("%s \n"
"%s \n"
+ "%s \n"
"void \n"
"%s(void *$__lldb_arg) \n"
"{ \n"
" %s; \n"
"} \n",
g_expression_prefix,
+ target_specific_defines,
m_prefix.c_str(),
m_name.c_str(),
m_body.c_str());
@@ -78,12 +103,14 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
case lldb::eLanguageTypeC_plus_plus:
wrap_stream.Printf("%s \n"
"%s \n"
+ "%s \n"
"void \n"
"$__lldb_class::%s(void *$__lldb_arg) %s\n"
"{ \n"
" %s; \n"
"} \n",
g_expression_prefix,
+ target_specific_defines,
m_prefix.c_str(),
m_name.c_str(),
(const_object ? "const" : ""),
@@ -94,6 +121,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
{
wrap_stream.Printf("%s \n"
"%s \n"
+ "%s \n"
"@interface $__lldb_objc_class ($__lldb_category) \n"
"+(void)%s:(void *)$__lldb_arg; \n"
"@end \n"
@@ -104,6 +132,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
"} \n"
"@end \n",
g_expression_prefix,
+ target_specific_defines,
m_prefix.c_str(),
m_name.c_str(),
m_name.c_str(),
@@ -113,6 +142,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
{
wrap_stream.Printf("%s \n"
"%s \n"
+ "%s \n"
"@interface $__lldb_objc_class ($__lldb_category) \n"
"-(void)%s:(void *)$__lldb_arg; \n"
"@end \n"
@@ -123,6 +153,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
"} \n"
"@end \n",
g_expression_prefix,
+ target_specific_defines,
m_prefix.c_str(),
m_name.c_str(),
m_name.c_str(),
diff --git a/source/Expression/IRDynamicChecks.cpp b/source/Expression/IRDynamicChecks.cpp
index a75a0fca9c62..aa5d28bb8aad 100644
--- a/source/Expression/IRDynamicChecks.cpp
+++ b/source/Expression/IRDynamicChecks.cpp
@@ -33,7 +33,7 @@ static char ID;
#define VALID_POINTER_CHECK_NAME "$__lldb_valid_pointer_check"
#define VALID_OBJC_OBJECT_CHECK_NAME "$__lldb_objc_object_check"
-static const char g_valid_pointer_check_text[] =
+static const char g_valid_pointer_check_text[] =
"extern \"C\" void\n"
"$__lldb_valid_pointer_check (unsigned char *$__lldb_arg_ptr)\n"
"{\n"
@@ -56,22 +56,22 @@ DynamicCheckerFunctions::Install(Stream &error_stream,
VALID_POINTER_CHECK_NAME));
if (!m_valid_pointer_check->Install(error_stream, exe_ctx))
return false;
-
+
Process *process = exe_ctx.GetProcessPtr();
if (process)
{
ObjCLanguageRuntime *objc_language_runtime = process->GetObjCLanguageRuntime();
-
+
if (objc_language_runtime)
{
m_objc_object_check.reset(objc_language_runtime->CreateObjectChecker(VALID_OBJC_OBJECT_CHECK_NAME));
-
+
if (!m_objc_object_check->Install(error_stream, exe_ctx))
return false;
}
}
-
+
return true;
}
@@ -94,7 +94,7 @@ DynamicCheckerFunctions::DoCheckersExplainStop (lldb::addr_t addr, Stream &messa
}
-static std::string
+static std::string
PrintValue(llvm::Value *V, bool truncate = false)
{
std::string s;
@@ -128,10 +128,10 @@ PrintValue(llvm::Value *V, bool truncate = false)
///
/// - InspectInstruction [default: does nothing]
///
-/// - InspectBasicBlock [default: iterates through the instructions in a
+/// - InspectBasicBlock [default: iterates through the instructions in a
/// basic block calling InspectInstruction]
///
-/// - InspectFunction [default: iterates through the basic blocks in a
+/// - InspectFunction [default: iterates through the basic blocks in a
/// function calling InspectBasicBlock]
//----------------------------------------------------------------------
class Instrumenter {
@@ -150,7 +150,7 @@ public:
m_intptr_ty(NULL)
{
}
-
+
virtual~Instrumenter ()
{
}
@@ -168,7 +168,7 @@ public:
{
return InspectFunction(function);
}
-
+
//------------------------------------------------------------------
/// Instrument all the instructions found by Inspect()
///
@@ -184,7 +184,7 @@ public:
if (!InstrumentInstruction(*ii))
return false;
}
-
+
return true;
}
protected:
@@ -192,13 +192,13 @@ protected:
/// Add instrumentation to a single instruction
///
/// @param[in] inst
- /// The instruction to be instrumented.
+ /// The instruction to be instrumented.
///
/// @return
/// True on success; false otherwise.
//------------------------------------------------------------------
virtual bool InstrumentInstruction(llvm::Instruction *inst) = 0;
-
+
//------------------------------------------------------------------
/// Register a single instruction to be instrumented
///
@@ -209,7 +209,7 @@ protected:
{
m_to_instrument.push_back(&i);
}
-
+
//------------------------------------------------------------------
/// Determine whether a single instruction is interesting to
/// instrument, and, if so, call RegisterInstruction
@@ -224,7 +224,7 @@ protected:
{
return true;
}
-
+
//------------------------------------------------------------------
/// Scan a basic block to see if any instructions are interesting
///
@@ -243,15 +243,15 @@ protected:
if (!InspectInstruction(*ii))
return false;
}
-
+
return true;
}
-
+
//------------------------------------------------------------------
/// Scan a function to see if any instructions are interesting
///
/// @param[in] f
- /// The function to be inspected.
+ /// The function to be inspected.
///
/// @return
/// False if there was an error scanning; true otherwise.
@@ -265,12 +265,12 @@ protected:
if (!InspectBasicBlock(*bbi))
return false;
}
-
+
return true;
}
-
+
//------------------------------------------------------------------
- /// Build a function pointer for a function with signature
+ /// Build a function pointer for a function with signature
/// void (*)(uint8_t*) with a given address
///
/// @param[in] start_address
@@ -282,19 +282,19 @@ protected:
llvm::Value *BuildPointerValidatorFunc(lldb::addr_t start_address)
{
llvm::Type *param_array[1];
-
+
param_array[0] = const_cast<llvm::PointerType*>(GetI8PtrTy());
-
+
ArrayRef<llvm::Type*> params(param_array, 1);
-
+
FunctionType *fun_ty = FunctionType::get(llvm::Type::getVoidTy(m_module.getContext()), params, true);
PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
Constant *fun_addr_int = ConstantInt::get(GetIntptrTy(), start_address, false);
return ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty);
}
-
+
//------------------------------------------------------------------
- /// Build a function pointer for a function with signature
+ /// Build a function pointer for a function with signature
/// void (*)(uint8_t*, uint8_t*) with a given address
///
/// @param[in] start_address
@@ -306,41 +306,41 @@ protected:
llvm::Value *BuildObjectCheckerFunc(lldb::addr_t start_address)
{
llvm::Type *param_array[2];
-
+
param_array[0] = const_cast<llvm::PointerType*>(GetI8PtrTy());
param_array[1] = const_cast<llvm::PointerType*>(GetI8PtrTy());
-
+
ArrayRef<llvm::Type*> params(param_array, 2);
-
+
FunctionType *fun_ty = FunctionType::get(llvm::Type::getVoidTy(m_module.getContext()), params, true);
PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
Constant *fun_addr_int = ConstantInt::get(GetIntptrTy(), start_address, false);
return ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty);
}
-
+
PointerType *GetI8PtrTy()
{
if (!m_i8ptr_ty)
m_i8ptr_ty = llvm::Type::getInt8PtrTy(m_module.getContext());
-
+
return m_i8ptr_ty;
}
-
+
IntegerType *GetIntptrTy()
{
if (!m_intptr_ty)
{
llvm::DataLayout data_layout(&m_module);
-
+
m_intptr_ty = llvm::Type::getIntNTy(m_module.getContext(), data_layout.getPointerSizeInBits());
}
-
+
return m_intptr_ty;
}
-
+
typedef std::vector <llvm::Instruction *> InstVector;
typedef InstVector::iterator InstIterator;
-
+
InstVector m_to_instrument; ///< List of instructions the inspector found
llvm::Module &m_module; ///< The module which is being instrumented
DynamicCheckerFunctions &m_checker_functions; ///< The dynamic checker functions for the process
@@ -358,7 +358,7 @@ public:
m_valid_pointer_check_func(NULL)
{
}
-
+
virtual ~ValidPointerChecker ()
{
}
@@ -368,53 +368,53 @@ private:
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (log)
- log->Printf("Instrumenting load/store instruction: %s\n",
+ log->Printf("Instrumenting load/store instruction: %s\n",
PrintValue(inst).c_str());
-
+
if (!m_valid_pointer_check_func)
m_valid_pointer_check_func = BuildPointerValidatorFunc(m_checker_functions.m_valid_pointer_check->StartAddress());
-
+
llvm::Value *dereferenced_ptr = NULL;
-
+
if (llvm::LoadInst *li = dyn_cast<llvm::LoadInst> (inst))
dereferenced_ptr = li->getPointerOperand();
else if (llvm::StoreInst *si = dyn_cast<llvm::StoreInst> (inst))
dereferenced_ptr = si->getPointerOperand();
else
return false;
-
+
// Insert an instruction to cast the loaded value to int8_t*
-
+
BitCastInst *bit_cast = new BitCastInst(dereferenced_ptr,
GetI8PtrTy(),
"",
inst);
-
+
// Insert an instruction to call the helper with the result
-
+
llvm::Value *arg_array[1];
-
+
arg_array[0] = bit_cast;
-
+
llvm::ArrayRef<llvm::Value *> args(arg_array, 1);
-
- CallInst::Create(m_valid_pointer_check_func,
+
+ CallInst::Create(m_valid_pointer_check_func,
args,
"",
inst);
-
+
return true;
}
-
+
bool InspectInstruction(llvm::Instruction &i)
{
if (dyn_cast<llvm::LoadInst> (&i) ||
dyn_cast<llvm::StoreInst> (&i))
RegisterInstruction(i);
-
+
return true;
}
-
+
llvm::Value *m_valid_pointer_check_func;
};
@@ -427,12 +427,12 @@ public:
m_objc_object_check_func(NULL)
{
}
-
+
virtual
~ObjcObjectChecker ()
{
}
-
+
enum msgSend_type
{
eMsgSend = 0,
@@ -441,25 +441,25 @@ public:
eMsgSend_fpret,
eMsgSend_stret
};
-
+
std::map <llvm::Instruction *, msgSend_type> msgSend_types;
private:
bool InstrumentInstruction(llvm::Instruction *inst)
{
CallInst *call_inst = dyn_cast<CallInst>(inst);
-
+
if (!call_inst)
return false; // call_inst really shouldn't be NULL, because otherwise InspectInstruction wouldn't have registered it
-
+
if (!m_objc_object_check_func)
m_objc_object_check_func = BuildObjectCheckerFunc(m_checker_functions.m_objc_object_check->StartAddress());
-
+
// id objc_msgSend(id theReceiver, SEL theSelector, ...)
-
+
llvm::Value *target_object;
llvm::Value *selector;
-
+
switch (msgSend_types[inst])
{
case eMsgSend:
@@ -475,119 +475,124 @@ private:
case eMsgSendSuper_stret:
return true;
}
-
+
// These objects should always be valid according to Sean Calannan
assert (target_object);
assert (selector);
// Insert an instruction to cast the receiver id to int8_t*
-
+
BitCastInst *bit_cast = new BitCastInst(target_object,
GetI8PtrTy(),
"",
inst);
-
+
// Insert an instruction to call the helper with the result
-
+
llvm::Value *arg_array[2];
-
+
arg_array[0] = bit_cast;
arg_array[1] = selector;
-
+
ArrayRef<llvm::Value*> args(arg_array, 2);
-
- CallInst::Create(m_objc_object_check_func,
+
+ CallInst::Create(m_objc_object_check_func,
args,
"",
inst);
-
+
return true;
}
-
+
bool InspectInstruction(llvm::Instruction &i)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
CallInst *call_inst = dyn_cast<CallInst>(&i);
-
+
if (call_inst)
{
// This metadata is set by IRForTarget::MaybeHandleCall().
-
+
MDNode *metadata = call_inst->getMetadata("lldb.call.realName");
-
+
if (!metadata)
return true;
-
+
if (metadata->getNumOperands() != 1)
{
if (log)
- log->Printf("Function call metadata has %d operands for [%p] %s", metadata->getNumOperands(), call_inst, PrintValue(call_inst).c_str());
+ log->Printf("Function call metadata has %d operands for [%p] %s",
+ metadata->getNumOperands(),
+ static_cast<void*>(call_inst),
+ PrintValue(call_inst).c_str());
return false;
}
-
+
MDString *real_name = dyn_cast<MDString>(metadata->getOperand(0));
-
+
if (!real_name)
{
if (log)
- log->Printf("Function call metadata is not an MDString for [%p] %s", call_inst, PrintValue(call_inst).c_str());
+ log->Printf("Function call metadata is not an MDString for [%p] %s",
+ static_cast<void*>(call_inst),
+ PrintValue(call_inst).c_str());
return false;
}
std::string name_str = real_name->getString();
const char* name_cstr = name_str.c_str();
-
+
if (log)
log->Printf("Found call to %s: %s\n", name_cstr, PrintValue(call_inst).c_str());
-
+
if (name_str.find("objc_msgSend") == std::string::npos)
return true;
-
+
if (!strcmp(name_cstr, "objc_msgSend"))
{
RegisterInstruction(i);
msgSend_types[&i] = eMsgSend;
return true;
}
-
+
if (!strcmp(name_cstr, "objc_msgSend_stret"))
{
RegisterInstruction(i);
msgSend_types[&i] = eMsgSend_stret;
return true;
}
-
+
if (!strcmp(name_cstr, "objc_msgSend_fpret"))
{
RegisterInstruction(i);
msgSend_types[&i] = eMsgSend_fpret;
return true;
}
-
+
if (!strcmp(name_cstr, "objc_msgSendSuper"))
{
RegisterInstruction(i);
msgSend_types[&i] = eMsgSendSuper;
return true;
}
-
+
if (!strcmp(name_cstr, "objc_msgSendSuper_stret"))
{
RegisterInstruction(i);
msgSend_types[&i] = eMsgSendSuper_stret;
return true;
}
-
+
if (log)
log->Printf("Function name '%s' contains 'objc_msgSend' but is not handled", name_str.c_str());
-
+
return true;
}
-
+
return true;
}
-
+
llvm::Value *m_objc_object_check_func;
};
@@ -607,52 +612,52 @@ bool
IRDynamicChecks::runOnModule(llvm::Module &M)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
llvm::Function* function = M.getFunction(StringRef(m_func_name.c_str()));
-
+
if (!function)
{
if (log)
log->Printf("Couldn't find %s() in the module", m_func_name.c_str());
-
+
return false;
}
if (m_checker_functions.m_valid_pointer_check.get())
{
ValidPointerChecker vpc(M, m_checker_functions);
-
+
if (!vpc.Inspect(*function))
return false;
-
+
if (!vpc.Instrument())
return false;
}
-
+
if (m_checker_functions.m_objc_object_check.get())
{
ObjcObjectChecker ooc(M, m_checker_functions);
-
+
if (!ooc.Inspect(*function))
return false;
-
+
if (!ooc.Instrument())
return false;
}
-
+
if (log && log->GetVerbose())
{
std::string s;
raw_string_ostream oss(s);
-
+
M.print(oss, NULL);
-
+
oss.flush();
-
+
log->Printf ("Module after dynamic checks: \n%s", s.c_str());
}
-
- return true;
+
+ return true;
}
void
diff --git a/source/Expression/IRExecutionUnit.cpp b/source/Expression/IRExecutionUnit.cpp
index 17bd03ae6cb5..090f88fc1bfe 100644
--- a/source/Expression/IRExecutionUnit.cpp
+++ b/source/Expression/IRExecutionUnit.cpp
@@ -7,18 +7,16 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/SourceMgr.h"
-// Project includes
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"
@@ -46,39 +44,39 @@ lldb::addr_t
IRExecutionUnit::WriteNow (const uint8_t *bytes,
size_t size,
Error &error)
-{
+{
lldb::addr_t allocation_process_addr = Malloc (size,
8,
lldb::ePermissionsWritable | lldb::ePermissionsReadable,
eAllocationPolicyMirror,
error);
-
+
if (!error.Success())
return LLDB_INVALID_ADDRESS;
-
+
WriteMemory(allocation_process_addr, bytes, size, error);
-
+
if (!error.Success())
{
Error err;
Free (allocation_process_addr, err);
-
+
return LLDB_INVALID_ADDRESS;
}
-
+
if (Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
{
DataBufferHeap my_buffer(size, 0);
Error err;
ReadMemory(my_buffer.GetBytes(), allocation_process_addr, size, err);
-
+
if (err.Success())
{
DataExtractor my_extractor(my_buffer.GetBytes(), my_buffer.GetByteSize(), lldb::eByteOrderBig, 8);
my_extractor.PutToLog(log, 0, my_buffer.GetByteSize(), allocation_process_addr, 16, DataExtractor::TypeUInt8);
}
}
-
+
return allocation_process_addr;
}
@@ -87,9 +85,9 @@ IRExecutionUnit::FreeNow (lldb::addr_t allocation)
{
if (allocation == LLDB_INVALID_ADDRESS)
return;
-
+
Error err;
-
+
Free(allocation, err);
}
@@ -98,16 +96,16 @@ IRExecutionUnit::DisassembleFunction (Stream &stream,
lldb::ProcessSP &process_wp)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
ExecutionContext exe_ctx(process_wp);
-
+
Error ret;
-
+
ret.Clear();
-
+
lldb::addr_t func_local_addr = LLDB_INVALID_ADDRESS;
lldb::addr_t func_remote_addr = LLDB_INVALID_ADDRESS;
-
+
for (JittedFunction &function : m_jitted_functions)
{
if (strstr(function.m_name.c_str(), m_name.AsCString()))
@@ -116,31 +114,31 @@ IRExecutionUnit::DisassembleFunction (Stream &stream,
func_remote_addr = function.m_remote_addr;
}
}
-
+
if (func_local_addr == LLDB_INVALID_ADDRESS)
{
ret.SetErrorToGenericError();
ret.SetErrorStringWithFormat("Couldn't find function %s for disassembly", m_name.AsCString());
return ret;
}
-
+
if (log)
log->Printf("Found function, has local address 0x%" PRIx64 " and remote address 0x%" PRIx64, (uint64_t)func_local_addr, (uint64_t)func_remote_addr);
-
+
std::pair <lldb::addr_t, lldb::addr_t> func_range;
-
+
func_range = GetRemoteRangeForLocal(func_local_addr);
-
+
if (func_range.first == 0 && func_range.second == 0)
{
ret.SetErrorToGenericError();
ret.SetErrorStringWithFormat("Couldn't find code range for function %s", m_name.AsCString());
return ret;
}
-
+
if (log)
log->Printf("Function's code range is [0x%" PRIx64 "+0x%" PRIx64 "]", func_range.first, func_range.second);
-
+
Target *target = exe_ctx.GetTargetPtr();
if (!target)
{
@@ -148,44 +146,44 @@ IRExecutionUnit::DisassembleFunction (Stream &stream,
ret.SetErrorString("Couldn't find the target");
return ret;
}
-
+
lldb::DataBufferSP buffer_sp(new DataBufferHeap(func_range.second, 0));
-
+
Process *process = exe_ctx.GetProcessPtr();
Error err;
process->ReadMemory(func_remote_addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), err);
-
+
if (!err.Success())
{
ret.SetErrorToGenericError();
ret.SetErrorStringWithFormat("Couldn't read from process: %s", err.AsCString("unknown error"));
return ret;
}
-
+
ArchSpec arch(target->GetArchitecture());
-
+
const char *plugin_name = NULL;
const char *flavor_string = NULL;
lldb::DisassemblerSP disassembler_sp = Disassembler::FindPlugin(arch, flavor_string, plugin_name);
-
+
if (!disassembler_sp)
{
ret.SetErrorToGenericError();
ret.SetErrorStringWithFormat("Unable to find disassembler plug-in for %s architecture.", arch.GetArchitectureName());
return ret;
}
-
+
if (!process)
{
ret.SetErrorToGenericError();
ret.SetErrorString("Couldn't find the process");
return ret;
}
-
+
DataExtractor extractor(buffer_sp,
process->GetByteOrder(),
target->GetArchitecture().GetAddressByteSize());
-
+
if (log)
{
log->Printf("Function data has contents:");
@@ -196,12 +194,12 @@ IRExecutionUnit::DisassembleFunction (Stream &stream,
16,
DataExtractor::TypeUInt8);
}
-
+
disassembler_sp->DecodeInstructions (Address (func_remote_addr), extractor, 0, UINT32_MAX, false, false);
-
+
InstructionList &instruction_list = disassembler_sp->GetInstructionList();
const uint32_t max_opcode_byte_size = instruction_list.GetMaxOpcocdeByteSize();
-
+
for (size_t instruction_index = 0, num_instructions = instruction_list.GetSize();
instruction_index < num_instructions;
++instruction_index)
@@ -223,7 +221,7 @@ IRExecutionUnit::DisassembleFunction (Stream &stream,
static void ReportInlineAsmError(const llvm::SMDiagnostic &diagnostic, void *Context, unsigned LocCookie)
{
Error *err = static_cast<Error*>(Context);
-
+
if (err && err->Success())
{
err->SetErrorToGenericError();
@@ -237,52 +235,52 @@ IRExecutionUnit::GetRunnableInfo(Error &error,
lldb::addr_t &func_end)
{
lldb::ProcessSP process_sp(GetProcessWP().lock());
-
+
static Mutex s_runnable_info_mutex(Mutex::Type::eMutexTypeRecursive);
-
+
func_addr = LLDB_INVALID_ADDRESS;
func_end = LLDB_INVALID_ADDRESS;
-
+
if (!process_sp)
{
error.SetErrorToGenericError();
error.SetErrorString("Couldn't write the JIT compiled code into the process because the process is invalid");
return;
}
-
+
if (m_did_jit)
{
func_addr = m_function_load_addr;
func_end = m_function_end_load_addr;
-
+
return;
};
-
+
Mutex::Locker runnable_info_mutex_locker(s_runnable_info_mutex);
-
+
m_did_jit = true;
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
std::string error_string;
-
+
if (log)
{
std::string s;
llvm::raw_string_ostream oss(s);
-
+
m_module->print(oss, NULL);
-
+
oss.flush();
-
+
log->Printf ("Module being sent to JIT: \n%s", s.c_str());
}
-
+
llvm::Triple triple(m_module->getTargetTriple());
llvm::Function *function = m_module->getFunction (m_name.AsCString());
llvm::Reloc::Model relocModel;
llvm::CodeModel::Model codeModel;
-
+
if (triple.isOSBinFormatELF())
{
relocModel = llvm::Reloc::Static;
@@ -294,11 +292,11 @@ IRExecutionUnit::GetRunnableInfo(Error &error,
relocModel = llvm::Reloc::PIC_;
codeModel = llvm::CodeModel::Small;
}
-
+
m_module_ap->getContext().setInlineAsmDiagnosticHandler(ReportInlineAsmError, &error);
-
- llvm::EngineBuilder builder(m_module_ap.get());
-
+
+ llvm::EngineBuilder builder(std::move(m_module_ap));
+
builder.setEngineKind(llvm::EngineKind::JIT)
.setErrorStr(&error_string)
.setRelocationModel(relocModel)
@@ -307,68 +305,67 @@ IRExecutionUnit::GetRunnableInfo(Error &error,
.setAllocateGVsWithCode(true)
.setCodeModel(codeModel)
.setUseMCJIT(true);
-
+
llvm::StringRef mArch;
llvm::StringRef mCPU;
llvm::SmallVector<std::string, 0> mAttrs;
-
+
for (std::string &feature : m_cpu_features)
mAttrs.push_back(feature);
-
+
llvm::TargetMachine *target_machine = builder.selectTarget(triple,
mArch,
mCPU,
mAttrs);
-
+
m_execution_engine_ap.reset(builder.create(target_machine));
-
+
if (!m_execution_engine_ap.get())
{
error.SetErrorToGenericError();
error.SetErrorStringWithFormat("Couldn't JIT the function: %s", error_string.c_str());
return;
}
- else
- {
- m_module_ap.release(); // ownership was transferred
- }
-
+
+ // Make sure we see all sections, including ones that don't have relocations...
+ m_execution_engine_ap->setProcessAllSections(true);
+
m_execution_engine_ap->DisableLazyCompilation();
-
+
// We don't actually need the function pointer here, this just forces it to get resolved.
-
+
void *fun_ptr = m_execution_engine_ap->getPointerToFunction(function);
-
+
if (!error.Success())
{
// We got an error through our callback!
return;
}
-
+
if (!function)
{
error.SetErrorToGenericError();
error.SetErrorStringWithFormat("Couldn't find '%s' in the JITted module", m_name.AsCString());
return;
}
-
+
if (!fun_ptr)
{
error.SetErrorToGenericError();
error.SetErrorStringWithFormat("'%s' was in the JITted module but wasn't lowered", m_name.AsCString());
return;
}
-
+
m_jitted_functions.push_back (JittedFunction(m_name.AsCString(), (lldb::addr_t)fun_ptr));
-
+
CommitAllocations(process_sp);
ReportAllocations(*m_execution_engine_ap);
WriteData(process_sp);
-
+
for (JittedFunction &jitted_function : m_jitted_functions)
{
jitted_function.m_remote_addr = GetRemoteAddressForLocal (jitted_function.m_local_addr);
-
+
if (!jitted_function.m_name.compare(m_name.AsCString()))
{
AddrRange func_range = GetRemoteRangeForLocal(jitted_function.m_local_addr);
@@ -376,15 +373,15 @@ IRExecutionUnit::GetRunnableInfo(Error &error,
m_function_load_addr = jitted_function.m_remote_addr;
}
}
-
+
if (log)
{
log->Printf("Code can be run in the target.");
-
+
StreamString disassembly_stream;
-
+
Error err = DisassembleFunction(disassembly_stream, process_sp);
-
+
if (!err.Success())
{
log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error"));
@@ -393,18 +390,18 @@ IRExecutionUnit::GetRunnableInfo(Error &error,
{
log->Printf("Function disassembly:\n%s", disassembly_stream.GetData());
}
-
+
log->Printf("Sections: ");
for (AllocationRecord &record : m_records)
{
if (record.m_process_address != LLDB_INVALID_ADDRESS)
{
record.dump(log);
-
+
DataBufferHeap my_buffer(record.m_size, 0);
Error err;
ReadMemory(my_buffer.GetBytes(), record.m_process_address, record.m_size, err);
-
+
if (err.Success())
{
DataExtractor my_extractor(my_buffer.GetBytes(), my_buffer.GetByteSize(), lldb::eByteOrderBig, 8);
@@ -413,10 +410,10 @@ IRExecutionUnit::GetRunnableInfo(Error &error,
}
}
}
-
+
func_addr = m_function_load_addr;
func_end = m_function_end_load_addr;
-
+
return;
}
@@ -433,6 +430,9 @@ IRExecutionUnit::MemoryManager::MemoryManager (IRExecutionUnit &parent) :
{
}
+IRExecutionUnit::MemoryManager::~MemoryManager ()
+{
+}
void
IRExecutionUnit::MemoryManager::setMemoryWritable ()
{
@@ -464,15 +464,19 @@ IRExecutionUnit::MemoryManager::allocateStub(const llvm::GlobalValue* F,
m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ GetSectionTypeFromSectionName (llvm::StringRef(), AllocationKind::Stub),
StubSize,
- Alignment));
+ Alignment,
+ eSectionIDInvalid,
+ NULL));
if (log)
{
log->Printf("IRExecutionUnit::allocateStub (F=%p, StubSize=%u, Alignment=%u) = %p",
- F, StubSize, Alignment, return_value);
+ static_cast<const void*>(F), StubSize, Alignment,
+ static_cast<void*>(return_value));
}
-
+
return return_value;
}
@@ -484,24 +488,136 @@ IRExecutionUnit::MemoryManager::endFunctionBody(const llvm::Function *F,
m_default_mm_ap->endFunctionBody(F, FunctionStart, FunctionEnd);
}
+lldb::SectionType
+IRExecutionUnit::GetSectionTypeFromSectionName (const llvm::StringRef &name, IRExecutionUnit::AllocationKind alloc_kind)
+{
+ lldb::SectionType sect_type = lldb::eSectionTypeCode;
+ switch (alloc_kind)
+ {
+ case AllocationKind::Stub: sect_type = lldb::eSectionTypeCode; break;
+ case AllocationKind::Code: sect_type = lldb::eSectionTypeCode; break;
+ case AllocationKind::Data: sect_type = lldb::eSectionTypeData; break;
+ case AllocationKind::Global:sect_type = lldb::eSectionTypeData; break;
+ case AllocationKind::Bytes: sect_type = lldb::eSectionTypeOther; break;
+ }
+
+ if (!name.empty())
+ {
+ if (name.equals("__text") || name.equals(".text"))
+ sect_type = lldb::eSectionTypeCode;
+ else if (name.equals("__data") || name.equals(".data"))
+ sect_type = lldb::eSectionTypeCode;
+ else if (name.startswith("__debug_") || name.startswith(".debug_"))
+ {
+ const uint32_t name_idx = name[0] == '_' ? 8 : 7;
+ llvm::StringRef dwarf_name(name.substr(name_idx));
+ switch (dwarf_name[0])
+ {
+ case 'a':
+ if (dwarf_name.equals("abbrev"))
+ sect_type = lldb::eSectionTypeDWARFDebugAbbrev;
+ else if (dwarf_name.equals("aranges"))
+ sect_type = lldb::eSectionTypeDWARFDebugAranges;
+ break;
+
+ case 'f':
+ if (dwarf_name.equals("frame"))
+ sect_type = lldb::eSectionTypeDWARFDebugFrame;
+ break;
+
+ case 'i':
+ if (dwarf_name.equals("info"))
+ sect_type = lldb::eSectionTypeDWARFDebugInfo;
+ break;
+
+ case 'l':
+ if (dwarf_name.equals("line"))
+ sect_type = lldb::eSectionTypeDWARFDebugLine;
+ else if (dwarf_name.equals("loc"))
+ sect_type = lldb::eSectionTypeDWARFDebugLoc;
+ break;
+
+ case 'm':
+ if (dwarf_name.equals("macinfo"))
+ sect_type = lldb::eSectionTypeDWARFDebugMacInfo;
+ break;
+
+ case 'p':
+ if (dwarf_name.equals("pubnames"))
+ sect_type = lldb::eSectionTypeDWARFDebugPubNames;
+ else if (dwarf_name.equals("pubtypes"))
+ sect_type = lldb::eSectionTypeDWARFDebugPubTypes;
+ break;
+
+ case 's':
+ if (dwarf_name.equals("str"))
+ sect_type = lldb::eSectionTypeDWARFDebugStr;
+ break;
+
+ case 'r':
+ if (dwarf_name.equals("ranges"))
+ sect_type = lldb::eSectionTypeDWARFDebugRanges;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if (name.startswith("__apple_") || name.startswith(".apple_"))
+ {
+#if 0
+ const uint32_t name_idx = name[0] == '_' ? 8 : 7;
+ llvm::StringRef apple_name(name.substr(name_idx));
+ switch (apple_name[0])
+ {
+ case 'n':
+ if (apple_name.equals("names"))
+ sect_type = lldb::eSectionTypeDWARFAppleNames;
+ else if (apple_name.equals("namespac") || apple_name.equals("namespaces"))
+ sect_type = lldb::eSectionTypeDWARFAppleNamespaces;
+ break;
+ case 't':
+ if (apple_name.equals("types"))
+ sect_type = lldb::eSectionTypeDWARFAppleTypes;
+ break;
+ case 'o':
+ if (apple_name.equals("objc"))
+ sect_type = lldb::eSectionTypeDWARFAppleObjC;
+ break;
+ default:
+ break;
+ }
+#else
+ sect_type = lldb::eSectionTypeInvalid;
+#endif
+ }
+ else if (name.equals("__objc_imageinfo"))
+ sect_type = lldb::eSectionTypeOther;
+ }
+ return sect_type;
+}
+
uint8_t *
IRExecutionUnit::MemoryManager::allocateSpace(intptr_t Size, unsigned Alignment)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
uint8_t *return_value = m_default_mm_ap->allocateSpace(Size, Alignment);
-
+
m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ GetSectionTypeFromSectionName (llvm::StringRef(), AllocationKind::Bytes),
Size,
- Alignment));
-
+ Alignment,
+ eSectionIDInvalid,
+ NULL));
+
if (log)
{
log->Printf("IRExecutionUnit::allocateSpace(Size=%" PRIu64 ", Alignment=%u) = %p",
(uint64_t)Size, Alignment, return_value);
}
-
+
return return_value;
}
@@ -512,21 +628,23 @@ IRExecutionUnit::MemoryManager::allocateCodeSection(uintptr_t Size,
llvm::StringRef SectionName)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
uint8_t *return_value = m_default_mm_ap->allocateCodeSection(Size, Alignment, SectionID, SectionName);
-
+
m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
lldb::ePermissionsReadable | lldb::ePermissionsExecutable,
+ GetSectionTypeFromSectionName (SectionName, AllocationKind::Code),
Size,
Alignment,
- SectionID));
-
+ SectionID,
+ SectionName.str().c_str()));
+
if (log)
{
log->Printf("IRExecutionUnit::allocateCodeSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p",
(uint64_t)Size, Alignment, SectionID, return_value);
}
-
+
return return_value;
}
@@ -540,19 +658,21 @@ IRExecutionUnit::MemoryManager::allocateDataSection(uintptr_t Size,
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
uint8_t *return_value = m_default_mm_ap->allocateDataSection(Size, Alignment, SectionID, SectionName, IsReadOnly);
-
+
m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
- lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ lldb::ePermissionsReadable | (IsReadOnly ? 0 : lldb::ePermissionsWritable),
+ GetSectionTypeFromSectionName (SectionName, AllocationKind::Data),
Size,
Alignment,
- SectionID));
+ SectionID,
+ SectionName.str().c_str()));
if (log)
{
log->Printf("IRExecutionUnit::allocateDataSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p",
(uint64_t)Size, Alignment, SectionID, return_value);
}
-
- return return_value;
+
+ return return_value;
}
uint8_t *
@@ -562,18 +682,21 @@ IRExecutionUnit::MemoryManager::allocateGlobal(uintptr_t Size,
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
uint8_t *return_value = m_default_mm_ap->allocateGlobal(Size, Alignment);
-
+
m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ GetSectionTypeFromSectionName (llvm::StringRef(), AllocationKind::Global),
Size,
- Alignment));
-
+ Alignment,
+ eSectionIDInvalid,
+ NULL));
+
if (log)
{
log->Printf("IRExecutionUnit::allocateGlobal(Size=0x%" PRIx64 ", Alignment=%u) = %p",
(uint64_t)Size, Alignment, return_value);
}
-
+
return return_value;
}
@@ -595,9 +718,9 @@ IRExecutionUnit::GetRemoteAddressForLocal (lldb::addr_t local_address)
{
if (record.m_process_address == LLDB_INVALID_ADDRESS)
return LLDB_INVALID_ADDRESS;
-
+
lldb::addr_t ret = record.m_process_address + (local_address - record.m_host_address);
-
+
if (log)
{
log->Printf("IRExecutionUnit::GetRemoteAddressForLocal() found 0x%" PRIx64 " in [0x%" PRIx64 "..0x%" PRIx64 "], and returned 0x%" PRIx64 " from [0x%" PRIx64 "..0x%" PRIx64 "].",
@@ -608,7 +731,7 @@ IRExecutionUnit::GetRemoteAddressForLocal (lldb::addr_t local_address)
record.m_process_address,
record.m_process_address + record.m_size);
}
-
+
return ret;
}
}
@@ -626,11 +749,11 @@ IRExecutionUnit::GetRemoteRangeForLocal (lldb::addr_t local_address)
{
if (record.m_process_address == LLDB_INVALID_ADDRESS)
return AddrRange(0, 0);
-
+
return AddrRange(record.m_process_address, record.m_size);
}
}
-
+
return AddrRange (0, 0);
}
@@ -638,28 +761,50 @@ bool
IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp)
{
bool ret = true;
-
+
lldb_private::Error err;
-
+
for (AllocationRecord &record : m_records)
{
if (record.m_process_address != LLDB_INVALID_ADDRESS)
continue;
-
-
- record.m_process_address = Malloc(record.m_size,
- record.m_alignment,
- record.m_permissions,
- eAllocationPolicyProcessOnly,
- err);
-
+
+ switch (record.m_sect_type)
+ {
+ case lldb::eSectionTypeInvalid:
+ case lldb::eSectionTypeDWARFDebugAbbrev:
+ case lldb::eSectionTypeDWARFDebugAranges:
+ case lldb::eSectionTypeDWARFDebugFrame:
+ case lldb::eSectionTypeDWARFDebugInfo:
+ case lldb::eSectionTypeDWARFDebugLine:
+ case lldb::eSectionTypeDWARFDebugLoc:
+ case lldb::eSectionTypeDWARFDebugMacInfo:
+ case lldb::eSectionTypeDWARFDebugPubNames:
+ case lldb::eSectionTypeDWARFDebugPubTypes:
+ case lldb::eSectionTypeDWARFDebugRanges:
+ case lldb::eSectionTypeDWARFDebugStr:
+ case lldb::eSectionTypeDWARFAppleNames:
+ case lldb::eSectionTypeDWARFAppleTypes:
+ case lldb::eSectionTypeDWARFAppleNamespaces:
+ case lldb::eSectionTypeDWARFAppleObjC:
+ err.Clear();
+ break;
+ default:
+ record.m_process_address = Malloc (record.m_size,
+ record.m_alignment,
+ record.m_permissions,
+ eAllocationPolicyProcessOnly,
+ err);
+ break;
+ }
+
if (!err.Success())
{
ret = false;
break;
}
}
-
+
if (!ret)
{
for (AllocationRecord &record : m_records)
@@ -671,7 +816,7 @@ IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp)
}
}
}
-
+
return ret;
}
@@ -682,13 +827,13 @@ IRExecutionUnit::ReportAllocations (llvm::ExecutionEngine &engine)
{
if (record.m_process_address == LLDB_INVALID_ADDRESS)
continue;
-
+
if (record.m_section_id == eSectionIDInvalid)
continue;
-
+
engine.mapSectionAddress((void*)record.m_host_address, record.m_process_address);
}
-
+
// Trigger re-application of relocations.
engine.finalizeObject();
}
@@ -696,25 +841,26 @@ IRExecutionUnit::ReportAllocations (llvm::ExecutionEngine &engine)
bool
IRExecutionUnit::WriteData (lldb::ProcessSP &process_sp)
{
+ bool wrote_something = false;
for (AllocationRecord &record : m_records)
{
- if (record.m_process_address == LLDB_INVALID_ADDRESS)
- return false;
-
- lldb_private::Error err;
-
- WriteMemory (record.m_process_address, (uint8_t*)record.m_host_address, record.m_size, err);
+ if (record.m_process_address != LLDB_INVALID_ADDRESS)
+ {
+ lldb_private::Error err;
+ WriteMemory (record.m_process_address, (uint8_t*)record.m_host_address, record.m_size, err);
+ if (err.Success())
+ wrote_something = true;
+ }
}
-
- return true;
+ return wrote_something;
}
-void
+void
IRExecutionUnit::AllocationRecord::dump (Log *log)
{
if (!log)
return;
-
+
log->Printf("[0x%llx+0x%llx]->0x%llx (alignment %d, section ID %d)",
(unsigned long long)m_host_address,
(unsigned long long)m_size,
@@ -722,3 +868,80 @@ IRExecutionUnit::AllocationRecord::dump (Log *log)
(unsigned)m_alignment,
(unsigned)m_section_id);
}
+
+
+lldb::ByteOrder
+IRExecutionUnit::GetByteOrder () const
+{
+ ExecutionContext exe_ctx (GetBestExecutionContextScope());
+ return exe_ctx.GetByteOrder();
+}
+
+uint32_t
+IRExecutionUnit::GetAddressByteSize () const
+{
+ ExecutionContext exe_ctx (GetBestExecutionContextScope());
+ return exe_ctx.GetAddressByteSize();
+}
+
+void
+IRExecutionUnit::PopulateSymtab (lldb_private::ObjectFile *obj_file,
+ lldb_private::Symtab &symtab)
+{
+ // No symbols yet...
+}
+
+
+void
+IRExecutionUnit::PopulateSectionList (lldb_private::ObjectFile *obj_file,
+ lldb_private::SectionList &section_list)
+{
+ for (AllocationRecord &record : m_records)
+ {
+ if (record.m_size > 0)
+ {
+ lldb::SectionSP section_sp (new lldb_private::Section (obj_file->GetModule(),
+ obj_file,
+ record.m_section_id,
+ ConstString(record.m_name),
+ record.m_sect_type,
+ record.m_process_address,
+ record.m_size,
+ record.m_host_address, // file_offset (which is the host address for the data)
+ record.m_size, // file_size
+ 0,
+ record.m_permissions)); // flags
+ section_list.AddSection (section_sp);
+ }
+ }
+}
+
+bool
+IRExecutionUnit::GetArchitecture (lldb_private::ArchSpec &arch)
+{
+ ExecutionContext exe_ctx (GetBestExecutionContextScope());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ arch = target->GetArchitecture();
+ else
+ arch.Clear();
+ return arch.IsValid();
+}
+
+lldb::ModuleSP
+IRExecutionUnit::GetJITModule ()
+{
+ ExecutionContext exe_ctx (GetBestExecutionContextScope());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ lldb::ModuleSP jit_module_sp = lldb_private::Module::CreateJITModule (std::static_pointer_cast<lldb_private::ObjectFileJITDelegate>(shared_from_this()));
+ if (jit_module_sp)
+ {
+ bool changed = false;
+ jit_module_sp->SetLoadAddress(*target, 0, true, changed);
+ }
+ return jit_module_sp;
+ }
+ return lldb::ModuleSP();
+}
diff --git a/source/Expression/IRForTarget.cpp b/source/Expression/IRForTarget.cpp
index a998896a98fd..b91e1b46f88e 100644
--- a/source/Expression/IRForTarget.cpp
+++ b/source/Expression/IRForTarget.cpp
@@ -59,7 +59,7 @@ IRForTarget::FunctionValueCache::~FunctionValueCache()
}
llvm::Value *IRForTarget::FunctionValueCache::GetValue(llvm::Function *function)
-{
+{
if (!m_values.count(function))
{
llvm::Value *ret = m_maker(function);
@@ -72,13 +72,13 @@ llvm::Value *IRForTarget::FunctionValueCache::GetValue(llvm::Function *function)
lldb::addr_t IRForTarget::StaticDataAllocator::Allocate()
{
lldb_private::Error err;
-
+
if (m_allocation != LLDB_INVALID_ADDRESS)
{
m_execution_unit.FreeNow(m_allocation);
m_allocation = LLDB_INVALID_ADDRESS;
}
-
+
m_allocation = m_execution_unit.WriteNow((const uint8_t*)m_stream_string.GetData(), m_stream_string.GetSize(), err);
return m_allocation;
@@ -88,7 +88,7 @@ static llvm::Value *FindEntryInstruction (llvm::Function *function)
{
if (function->empty())
return NULL;
-
+
return function->getEntryBlock().getFirstNonPHIOrDbg();
}
@@ -116,7 +116,7 @@ IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
/* Handy utility functions used at several places in the code */
-static std::string
+static std::string
PrintValue(const Value *value, bool truncate = false)
{
std::string s;
@@ -151,38 +151,38 @@ bool
IRForTarget::FixFunctionLinkage(llvm::Function &llvm_function)
{
llvm_function.setLinkage(GlobalValue::ExternalLinkage);
-
+
std::string name = llvm_function.getName().str();
-
+
return true;
}
-bool
+IRForTarget::LookupResult
IRForTarget::GetFunctionAddress (llvm::Function *fun,
uint64_t &fun_addr,
lldb_private::ConstString &name,
Constant **&value_ptr)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
fun_addr = LLDB_INVALID_ADDRESS;
name.Clear();
value_ptr = NULL;
-
+
if (fun->isIntrinsic())
{
Intrinsic::ID intrinsic_id = (Intrinsic::ID)fun->getIntrinsicID();
-
+
switch (intrinsic_id)
{
default:
if (log)
log->Printf("Unresolved intrinsic \"%s\"", Intrinsic::getName(intrinsic_id).c_str());
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Call to unhandled compiler intrinsic '%s'\n", Intrinsic::getName(intrinsic_id).c_str());
-
- return false;
+
+ return LookupResult::Fail;
case Intrinsic::memcpy:
{
static lldb_private::ConstString g_memcpy_str ("memcpy");
@@ -195,8 +195,11 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun,
name = g_memset_str;
}
break;
+ case Intrinsic::dbg_declare:
+ case Intrinsic::dbg_value:
+ return LookupResult::Ignore;
}
-
+
if (log && name)
log->Printf("Resolved intrinsic name \"%s\"", name.GetCString());
}
@@ -204,14 +207,14 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun,
{
name.SetCStringWithLength (fun->getName().data(), fun->getName().size());
}
-
+
// Find the address of the function.
-
+
clang::NamedDecl *fun_decl = DeclForGlobal (fun);
-
+
if (fun_decl)
{
- if (!m_decl_map->GetFunctionInfo (fun_decl, fun_addr))
+ if (!m_decl_map->GetFunctionInfo (fun_decl, fun_addr))
{
lldb_private::ConstString altnernate_name;
bool found_it = m_decl_map->GetFunctionAddress (name, fun_addr);
@@ -228,7 +231,7 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun,
found_it = m_decl_map->GetFunctionAddress (altnernate_name, fun_addr);
}
}
-
+
if (!found_it)
{
lldb_private::Mangled mangled_name(name);
@@ -243,7 +246,7 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun,
log->Printf("Function \"%s\" had no address",
mangled_name.GetName().GetCString());
}
-
+
if (m_error_stream)
{
if (alt_mangled_name)
@@ -258,28 +261,28 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun,
m_error_stream->Printf("error: call to a function '%s' that is not present in the target\n",
mangled_name.GetName().GetCString());
}
- return false;
+ return LookupResult::Fail;
}
}
}
- else
+ else
{
if (!m_decl_map->GetFunctionAddress (name, fun_addr))
{
if (log)
log->Printf ("Metadataless function \"%s\" had no address", name.GetCString());
-
+
if (m_error_stream)
m_error_stream->Printf("Error [IRForTarget]: Call to a symbol-only function '%s' that is not present in the target\n", name.GetCString());
-
- return false;
+
+ return LookupResult::Fail;
}
}
-
+
if (log)
log->Printf("Found \"%s\" at 0x%" PRIx64, name.GetCString(), fun_addr);
-
- return true;
+
+ return LookupResult::Success;
}
llvm::Constant *
@@ -293,15 +296,11 @@ IRForTarget::BuildFunctionPointer (llvm::Type *type,
void
IRForTarget::RegisterFunctionMetadata(LLVMContext &context,
- llvm::Value *function_ptr,
+ llvm::Value *function_ptr,
const char *name)
{
- for (Value::use_iterator i = function_ptr->use_begin(), e = function_ptr->use_end();
- i != e;
- ++i)
+ for (llvm::User *user : function_ptr->users())
{
- Value *user = *i;
-
if (Instruction *user_inst = dyn_cast<Instruction>(user))
{
MDString* md_name = MDString::get(context, StringRef(name));
@@ -317,62 +316,74 @@ IRForTarget::RegisterFunctionMetadata(LLVMContext &context,
}
}
-bool
+bool
IRForTarget::ResolveFunctionPointers(llvm::Module &llvm_module)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
for (llvm::Module::iterator fi = llvm_module.begin();
fi != llvm_module.end();
++fi)
{
Function *fun = fi;
-
+
bool is_decl = fun->isDeclaration();
-
+
if (log)
log->Printf("Examining %s function %s", (is_decl ? "declaration" : "non-declaration"), fun->getName().str().c_str());
-
+
if (!is_decl)
continue;
-
- if (fun->hasNUses(0))
+
+ if (fun->use_empty())
continue; // ignore
-
+
uint64_t addr = LLDB_INVALID_ADDRESS;
lldb_private::ConstString name;
Constant **value_ptr = NULL;
-
- if (!GetFunctionAddress(fun,
- addr,
- name,
- value_ptr))
+
+ LookupResult result = GetFunctionAddress(fun,
+ addr,
+ name,
+ value_ptr);
+
+ switch (result)
+ {
+ case LookupResult::Fail:
return false; // GetFunctionAddress reports its own errors
-
- Constant *value = BuildFunctionPointer(fun->getFunctionType(), addr);
-
- RegisterFunctionMetadata (llvm_module.getContext(), fun, name.AsCString());
-
- if (value_ptr)
- *value_ptr = value;
-
- // If we are replacing a function with the nobuiltin attribute, it may
- // be called with the builtin attribute on call sites. Remove any such
- // attributes since it's illegal to have a builtin call to something
- // other than a nobuiltin function.
- if (fun->hasFnAttribute(llvm::Attribute::NoBuiltin)) {
- llvm::Attribute builtin = llvm::Attribute::get(fun->getContext(), llvm::Attribute::Builtin);
-
- for (auto u = fun->use_begin(), e = fun->use_end(); u != e; ++u) {
- if (auto call = dyn_cast<CallInst>(*u)) {
- call->removeAttribute(AttributeSet::FunctionIndex, builtin);
+
+ case LookupResult::Ignore:
+ break; // Nothing to do
+
+ case LookupResult::Success:
+ {
+ Constant *value = BuildFunctionPointer(fun->getFunctionType(), addr);
+
+ RegisterFunctionMetadata (llvm_module.getContext(), fun, name.AsCString());
+
+ if (value_ptr)
+ *value_ptr = value;
+
+ // If we are replacing a function with the nobuiltin attribute, it may
+ // be called with the builtin attribute on call sites. Remove any such
+ // attributes since it's illegal to have a builtin call to something
+ // other than a nobuiltin function.
+ if (fun->hasFnAttribute(llvm::Attribute::NoBuiltin)) {
+ llvm::Attribute builtin = llvm::Attribute::get(fun->getContext(), llvm::Attribute::Builtin);
+
+ for (auto u : fun->users()) {
+ if (auto call = dyn_cast<CallInst>(u)) {
+ call->removeAttribute(AttributeSet::FunctionIndex, builtin);
+ }
+ }
}
+
+ fun->replaceAllUsesWith(value);
}
+ break;
}
-
- fun->replaceAllUsesWith(value);
}
-
+
return true;
}
@@ -381,69 +392,69 @@ clang::NamedDecl *
IRForTarget::DeclForGlobal (const GlobalValue *global_val, Module *module)
{
NamedMDNode *named_metadata = module->getNamedMetadata("clang.global.decl.ptrs");
-
+
if (!named_metadata)
return NULL;
-
+
unsigned num_nodes = named_metadata->getNumOperands();
unsigned node_index;
-
+
for (node_index = 0;
node_index < num_nodes;
++node_index)
{
MDNode *metadata_node = named_metadata->getOperand(node_index);
-
+
if (!metadata_node)
return NULL;
-
+
if (metadata_node->getNumOperands() != 2)
continue;
-
+
if (metadata_node->getOperand(0) != global_val)
continue;
-
+
ConstantInt *constant_int = dyn_cast<ConstantInt>(metadata_node->getOperand(1));
-
+
if (!constant_int)
return NULL;
-
+
uintptr_t ptr = constant_int->getZExtValue();
-
+
return reinterpret_cast<clang::NamedDecl *>(ptr);
}
-
+
return NULL;
}
clang::NamedDecl *
IRForTarget::DeclForGlobal (GlobalValue *global_val)
-{
+{
return DeclForGlobal(global_val, m_module);
}
-bool
+bool
IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (!m_resolve_vars)
return true;
-
+
// Find the result variable. If it doesn't exist, we can give up right here.
-
+
ValueSymbolTable& value_symbol_table = m_module->getValueSymbolTable();
-
+
std::string result_name_str;
const char *result_name = NULL;
-
+
for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end();
vi != ve;
++vi)
{
result_name_str = vi->first().str();
const char *value_name = result_name_str.c_str();
-
+
if (strstr(value_name, "$__lldb_expr_result_ptr") &&
strncmp(value_name, "_ZGV", 4))
{
@@ -451,7 +462,7 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
m_result_is_pointer = true;
break;
}
-
+
if (strstr(value_name, "$__lldb_expr_result") &&
strncmp(value_name, "_ZGV", 4))
{
@@ -460,105 +471,105 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
break;
}
}
-
+
if (!result_name)
{
if (log)
log->PutCString("Couldn't find result variable");
-
+
return true;
}
-
+
if (log)
log->Printf("Result name: \"%s\"", result_name);
-
+
Value *result_value = m_module->getNamedValue(result_name);
-
+
if (!result_value)
{
if (log)
log->PutCString("Result variable had no data");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Result variable's name (%s) exists, but not its definition\n", result_name);
-
+
return false;
}
-
+
if (log)
log->Printf("Found result in the IR: \"%s\"", PrintValue(result_value, false).c_str());
-
+
GlobalVariable *result_global = dyn_cast<GlobalVariable>(result_value);
-
+
if (!result_global)
{
if (log)
log->PutCString("Result variable isn't a GlobalVariable");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s) is defined, but is not a global variable\n", result_name);
-
+
return false;
}
-
+
clang::NamedDecl *result_decl = DeclForGlobal (result_global);
if (!result_decl)
{
if (log)
log->PutCString("Result variable doesn't have a corresponding Decl");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s) does not have a corresponding Clang entity\n", result_name);
-
+
return false;
}
-
+
if (log)
{
std::string decl_desc_str;
raw_string_ostream decl_desc_stream(decl_desc_str);
result_decl->print(decl_desc_stream);
decl_desc_stream.flush();
-
+
log->Printf("Found result decl: \"%s\"", decl_desc_str.c_str());
}
-
+
clang::VarDecl *result_var = dyn_cast<clang::VarDecl>(result_decl);
if (!result_var)
{
if (log)
log->PutCString("Result variable Decl isn't a VarDecl");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s)'s corresponding Clang entity isn't a variable\n", result_name);
-
+
return false;
}
-
+
// Get the next available result name from m_decl_map and create the persistent
// variable for it
-
+
// If the result is an Lvalue, it is emitted as a pointer; see
// ASTResultSynthesizer::SynthesizeBodyResult.
if (m_result_is_pointer)
{
clang::QualType pointer_qual_type = result_var->getType();
const clang::Type *pointer_type = pointer_qual_type.getTypePtr();
-
+
const clang::PointerType *pointer_pointertype = pointer_type->getAs<clang::PointerType>();
const clang::ObjCObjectPointerType *pointer_objcobjpointertype = pointer_type->getAs<clang::ObjCObjectPointerType>();
-
+
if (pointer_pointertype)
{
clang::QualType element_qual_type = pointer_pointertype->getPointeeType();
-
+
m_result_type = lldb_private::TypeFromParser(element_qual_type.getAsOpaquePtr(),
&result_decl->getASTContext());
}
else if (pointer_objcobjpointertype)
{
clang::QualType element_qual_type = clang::QualType(pointer_objcobjpointertype->getObjectType(), 0);
-
+
m_result_type = lldb_private::TypeFromParser(element_qual_type.getAsOpaquePtr(),
&result_decl->getASTContext());
}
@@ -566,10 +577,10 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
{
if (log)
log->PutCString("Expected result to have pointer type, but it did not");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Lvalue result (%s) is not a pointer variable\n", result_name);
-
+
return false;
}
}
@@ -578,99 +589,99 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
m_result_type = lldb_private::TypeFromParser(result_var->getType().getAsOpaquePtr(),
&result_decl->getASTContext());
}
-
+
if (m_result_type.GetBitSize() == 0)
{
lldb_private::StreamString type_desc_stream;
m_result_type.DumpTypeDescription(&type_desc_stream);
-
+
if (log)
log->Printf("Result type has size 0");
-
+
if (m_error_stream)
- m_error_stream->Printf("Error [IRForTarget]: Size of result type '%s' couldn't be determined\n",
+ m_error_stream->Printf("Error [IRForTarget]: Size of result type '%s' couldn't be determined\n",
type_desc_stream.GetData());
return false;
}
-
+
if (log)
{
lldb_private::StreamString type_desc_stream;
m_result_type.DumpTypeDescription(&type_desc_stream);
-
+
log->Printf("Result decl type: \"%s\"", type_desc_stream.GetData());
}
-
+
m_result_name = lldb_private::ConstString("$RESULT_NAME");
-
+
if (log)
log->Printf("Creating a new result global: \"%s\" with size 0x%" PRIx64,
m_result_name.GetCString(),
m_result_type.GetByteSize());
-
+
// Construct a new result global and set up its metadata
-
- GlobalVariable *new_result_global = new GlobalVariable((*m_module),
+
+ GlobalVariable *new_result_global = new GlobalVariable((*m_module),
result_global->getType()->getElementType(),
false, /* not constant */
GlobalValue::ExternalLinkage,
NULL, /* no initializer */
m_result_name.GetCString ());
-
+
// It's too late in compilation to create a new VarDecl for this, but we don't
// need to. We point the metadata at the old VarDecl. This creates an odd
// anomaly: a variable with a Value whose name is something like $0 and a
// Decl whose name is $__lldb_expr_result. This condition is handled in
// ClangExpressionDeclMap::DoMaterialize, and the name of the variable is
// fixed up.
-
+
ConstantInt *new_constant_int = ConstantInt::get(llvm::Type::getInt64Ty(m_module->getContext()),
reinterpret_cast<uint64_t>(result_decl),
false);
-
+
llvm::Value* values[2];
values[0] = new_result_global;
values[1] = new_constant_int;
-
+
ArrayRef<Value*> value_ref(values, 2);
-
+
MDNode *persistent_global_md = MDNode::get(m_module->getContext(), value_ref);
NamedMDNode *named_metadata = m_module->getNamedMetadata("clang.global.decl.ptrs");
named_metadata->addOperand(persistent_global_md);
-
+
if (log)
log->Printf("Replacing \"%s\" with \"%s\"",
PrintValue(result_global).c_str(),
PrintValue(new_result_global).c_str());
-
- if (result_global->hasNUses(0))
+
+ if (result_global->use_empty())
{
// We need to synthesize a store for this variable, because otherwise
// there's nothing to put into its equivalent persistent variable.
-
+
BasicBlock &entry_block(llvm_function.getEntryBlock());
Instruction *first_entry_instruction(entry_block.getFirstNonPHIOrDbg());
-
+
if (!first_entry_instruction)
return false;
-
+
if (!result_global->hasInitializer())
{
if (log)
log->Printf("Couldn't find initializer for unused variable");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s) has no writes and no initializer\n", result_name);
-
+
return false;
}
-
+
Constant *initializer = result_global->getInitializer();
-
+
StoreInst *synthesized_store = new StoreInst(initializer,
new_result_global,
first_entry_instruction);
-
+
if (log)
log->Printf("Synthesized result store \"%s\"\n", PrintValue(synthesized_store).c_str());
}
@@ -678,76 +689,51 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
{
result_global->replaceAllUsesWith(new_result_global);
}
-
+
if (!m_decl_map->AddPersistentVariable(result_decl,
- m_result_name,
+ m_result_name,
m_result_type,
true,
m_result_is_pointer))
return false;
-
+
result_global->eraseFromParent();
-
- return true;
-}
-#if 0
-static void DebugUsers(Log *log, Value *value, uint8_t depth)
-{
- if (!depth)
- return;
-
- depth--;
-
- if (log)
- log->Printf(" <Begin %d users>", value->getNumUses());
-
- for (Value::use_iterator ui = value->use_begin(), ue = value->use_end();
- ui != ue;
- ++ui)
- {
- if (log)
- log->Printf(" <Use %p> %s", *ui, PrintValue(*ui).c_str());
- DebugUsers(log, *ui, depth);
- }
-
- if (log)
- log->Printf(" <End uses>");
+ return true;
}
-#endif
bool
IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str,
llvm::GlobalVariable *cstr)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
Type *ns_str_ty = ns_str->getType();
-
+
Type *i8_ptr_ty = Type::getInt8PtrTy(m_module->getContext());
Type *i32_ty = Type::getInt32Ty(m_module->getContext());
Type *i8_ty = Type::getInt8Ty(m_module->getContext());
-
+
if (!m_CFStringCreateWithBytes)
{
lldb::addr_t CFStringCreateWithBytes_addr;
-
+
static lldb_private::ConstString g_CFStringCreateWithBytes_str ("CFStringCreateWithBytes");
-
+
if (!m_decl_map->GetFunctionAddress (g_CFStringCreateWithBytes_str, CFStringCreateWithBytes_addr))
{
if (log)
log->PutCString("Couldn't find CFStringCreateWithBytes in the target");
-
+
if (m_error_stream)
m_error_stream->Printf("Error [IRForTarget]: Rewriting an Objective-C constant string requires CFStringCreateWithBytes\n");
-
+
return false;
}
-
+
if (log)
log->Printf("Found CFStringCreateWithBytes at 0x%" PRIx64, CFStringCreateWithBytes_addr);
-
+
// Build the function type:
//
// CFStringRef CFStringCreateWithBytes (
@@ -766,66 +752,66 @@ IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str,
// CFIndex -> long (i32 or i64, as appropriate; we ask the module for its pointer size for now)
// CFStringEncoding -> i32
// Boolean -> i8
-
+
Type *arg_type_array[5];
-
+
arg_type_array[0] = i8_ptr_ty;
arg_type_array[1] = i8_ptr_ty;
arg_type_array[2] = m_intptr_ty;
arg_type_array[3] = i32_ty;
arg_type_array[4] = i8_ty;
-
+
ArrayRef<Type *> CFSCWB_arg_types(arg_type_array, 5);
-
+
llvm::Type *CFSCWB_ty = FunctionType::get(ns_str_ty, CFSCWB_arg_types, false);
-
+
// Build the constant containing the pointer to the function
PointerType *CFSCWB_ptr_ty = PointerType::getUnqual(CFSCWB_ty);
Constant *CFSCWB_addr_int = ConstantInt::get(m_intptr_ty, CFStringCreateWithBytes_addr, false);
m_CFStringCreateWithBytes = ConstantExpr::getIntToPtr(CFSCWB_addr_int, CFSCWB_ptr_ty);
}
-
+
ConstantDataSequential *string_array = NULL;
-
+
if (cstr)
string_array = dyn_cast<ConstantDataSequential>(cstr->getInitializer());
-
+
Constant *alloc_arg = Constant::getNullValue(i8_ptr_ty);
Constant *bytes_arg = cstr ? ConstantExpr::getBitCast(cstr, i8_ptr_ty) : Constant::getNullValue(i8_ptr_ty);
Constant *numBytes_arg = ConstantInt::get(m_intptr_ty, cstr ? string_array->getNumElements() - 1 : 0, false);
Constant *encoding_arg = ConstantInt::get(i32_ty, 0x0600, false); /* 0x0600 is kCFStringEncodingASCII */
Constant *isExternal_arg = ConstantInt::get(i8_ty, 0x0, false); /* 0x0 is false */
-
+
Value *argument_array[5];
-
+
argument_array[0] = alloc_arg;
argument_array[1] = bytes_arg;
argument_array[2] = numBytes_arg;
argument_array[3] = encoding_arg;
argument_array[4] = isExternal_arg;
-
+
ArrayRef <Value *> CFSCWB_arguments(argument_array, 5);
-
+
FunctionValueCache CFSCWB_Caller ([this, &CFSCWB_arguments] (llvm::Function *function)->llvm::Value * {
return CallInst::Create(m_CFStringCreateWithBytes,
CFSCWB_arguments,
"CFStringCreateWithBytes",
llvm::cast<Instruction>(m_entry_instruction_finder.GetValue(function)));
});
-
+
if (!UnfoldConstant(ns_str, CFSCWB_Caller, m_entry_instruction_finder))
{
if (log)
log->PutCString("Couldn't replace the NSString with the result of the call");
-
+
if (m_error_stream)
m_error_stream->Printf("Error [IRForTarget]: Couldn't replace an Objective-C constant string with a dynamic string\n");
-
+
return false;
}
-
+
ns_str->eraseFromParent();
-
+
return true;
}
@@ -833,57 +819,57 @@ bool
IRForTarget::RewriteObjCConstStrings()
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
ValueSymbolTable& value_symbol_table = m_module->getValueSymbolTable();
-
+
for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end();
vi != ve;
++vi)
{
std::string value_name = vi->first().str();
const char *value_name_cstr = value_name.c_str();
-
+
if (strstr(value_name_cstr, "_unnamed_cfstring_"))
{
Value *nsstring_value = vi->second;
-
+
GlobalVariable *nsstring_global = dyn_cast<GlobalVariable>(nsstring_value);
-
+
if (!nsstring_global)
{
if (log)
log->PutCString("NSString variable is not a GlobalVariable");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string is not a global variable\n");
-
+
return false;
}
-
+
if (!nsstring_global->hasInitializer())
{
if (log)
log->PutCString("NSString variable does not have an initializer");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string does not have an initializer\n");
-
+
return false;
}
-
+
ConstantStruct *nsstring_struct = dyn_cast<ConstantStruct>(nsstring_global->getInitializer());
-
+
if (!nsstring_struct)
{
if (log)
log->PutCString("NSString variable's initializer is not a ConstantStruct");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string is not a structure constant\n");
-
+
return false;
}
-
+
// We expect the following structure:
//
// struct {
@@ -892,107 +878,107 @@ IRForTarget::RewriteObjCConstStrings()
// char *str;
// long length;
// };
-
+
if (nsstring_struct->getNumOperands() != 4)
{
if (log)
log->Printf("NSString variable's initializer structure has an unexpected number of members. Should be 4, is %d", nsstring_struct->getNumOperands());
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: The struct for an Objective-C constant string is not as expected\n");
-
+
return false;
}
-
+
Constant *nsstring_member = nsstring_struct->getOperand(2);
-
+
if (!nsstring_member)
{
if (log)
log->PutCString("NSString initializer's str element was empty");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string does not have a string initializer\n");
-
+
return false;
}
-
+
ConstantExpr *nsstring_expr = dyn_cast<ConstantExpr>(nsstring_member);
-
+
if (!nsstring_expr)
{
if (log)
log->PutCString("NSString initializer's str element is not a ConstantExpr");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer is not constant\n");
-
+
return false;
}
-
+
if (nsstring_expr->getOpcode() != Instruction::GetElementPtr)
{
if (log)
log->Printf("NSString initializer's str element is not a GetElementPtr expression, it's a %s", nsstring_expr->getOpcodeName());
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer is not an array\n");
-
+
return false;
}
-
+
Constant *nsstring_cstr = nsstring_expr->getOperand(0);
-
+
GlobalVariable *cstr_global = dyn_cast<GlobalVariable>(nsstring_cstr);
-
+
if (!cstr_global)
{
if (log)
log->PutCString("NSString initializer's str element is not a GlobalVariable");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer doesn't point to a global\n");
-
+
return false;
}
-
+
if (!cstr_global->hasInitializer())
{
if (log)
log->PutCString("NSString initializer's str element does not have an initializer");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer doesn't point to initialized data\n");
-
+
return false;
}
-
+
/*
if (!cstr_array)
{
if (log)
log->PutCString("NSString initializer's str element is not a ConstantArray");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer doesn't point to an array\n");
-
+
return false;
}
-
+
if (!cstr_array->isCString())
{
if (log)
log->PutCString("NSString initializer's str element is not a C string array");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer doesn't point to a C string\n");
-
+
return false;
}
*/
-
+
ConstantDataArray *cstr_array = dyn_cast<ConstantDataArray>(cstr_global->getInitializer());
-
+
if (log)
{
if (cstr_array)
@@ -1000,175 +986,175 @@ IRForTarget::RewriteObjCConstStrings()
else
log->Printf("Found NSString constant %s, which contains \"\"", value_name_cstr);
}
-
+
if (!cstr_array)
cstr_global = NULL;
-
+
if (!RewriteObjCConstString(nsstring_global, cstr_global))
- {
+ {
if (log)
log->PutCString("Error rewriting the constant string");
-
+
// We don't print an error message here because RewriteObjCConstString has done so for us.
-
+
return false;
}
}
}
-
+
for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end();
vi != ve;
++vi)
{
std::string value_name = vi->first().str();
const char *value_name_cstr = value_name.c_str();
-
+
if (!strcmp(value_name_cstr, "__CFConstantStringClassReference"))
{
GlobalVariable *gv = dyn_cast<GlobalVariable>(vi->second);
-
+
if (!gv)
{
if (log)
log->PutCString("__CFConstantStringClassReference is not a global variable");
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Found a CFConstantStringClassReference, but it is not a global object\n");
-
+
return false;
}
-
+
gv->eraseFromParent();
-
+
break;
}
}
-
+
return true;
}
static bool IsObjCSelectorRef (Value *value)
{
GlobalVariable *global_variable = dyn_cast<GlobalVariable>(value);
-
+
if (!global_variable || !global_variable->hasName() || !global_variable->getName().startswith("\01L_OBJC_SELECTOR_REFERENCES_"))
return false;
-
+
return true;
}
// This function does not report errors; its callers are responsible.
-bool
+bool
IRForTarget::RewriteObjCSelector (Instruction* selector_load)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
LoadInst *load = dyn_cast<LoadInst>(selector_load);
-
+
if (!load)
return false;
-
+
// Unpack the message name from the selector. In LLVM IR, an objc_msgSend gets represented as
//
// %tmp = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_" ; <i8*>
// %call = call i8* (i8*, i8*, ...)* @objc_msgSend(i8* %obj, i8* %tmp, ...) ; <i8*>
//
// where %obj is the object pointer and %tmp is the selector.
- //
+ //
// @"\01L_OBJC_SELECTOR_REFERENCES_" is a pointer to a character array called @"\01L_OBJC_llvm_moduleETH_VAR_NAllvm_moduleE_".
// @"\01L_OBJC_llvm_moduleETH_VAR_NAllvm_moduleE_" contains the string.
-
+
// Find the pointer's initializer (a ConstantExpr with opcode GetElementPtr) and get the string from its target
-
+
GlobalVariable *_objc_selector_references_ = dyn_cast<GlobalVariable>(load->getPointerOperand());
-
+
if (!_objc_selector_references_ || !_objc_selector_references_->hasInitializer())
return false;
-
+
Constant *osr_initializer = _objc_selector_references_->getInitializer();
-
+
ConstantExpr *osr_initializer_expr = dyn_cast<ConstantExpr>(osr_initializer);
-
+
if (!osr_initializer_expr || osr_initializer_expr->getOpcode() != Instruction::GetElementPtr)
return false;
-
+
Value *osr_initializer_base = osr_initializer_expr->getOperand(0);
if (!osr_initializer_base)
return false;
-
+
// Find the string's initializer (a ConstantArray) and get the string from it
-
+
GlobalVariable *_objc_meth_var_name_ = dyn_cast<GlobalVariable>(osr_initializer_base);
-
+
if (!_objc_meth_var_name_ || !_objc_meth_var_name_->hasInitializer())
return false;
-
+
Constant *omvn_initializer = _objc_meth_var_name_->getInitializer();
ConstantDataArray *omvn_initializer_array = dyn_cast<ConstantDataArray>(omvn_initializer);
-
+
if (!omvn_initializer_array->isString())
return false;
-
+
std::string omvn_initializer_string = omvn_initializer_array->getAsString();
-
+
if (log)
log->Printf("Found Objective-C selector reference \"%s\"", omvn_initializer_string.c_str());
-
+
// Construct a call to sel_registerName
-
+
if (!m_sel_registerName)
{
lldb::addr_t sel_registerName_addr;
-
+
static lldb_private::ConstString g_sel_registerName_str ("sel_registerName");
if (!m_decl_map->GetFunctionAddress (g_sel_registerName_str, sel_registerName_addr))
return false;
-
+
if (log)
log->Printf("Found sel_registerName at 0x%" PRIx64, sel_registerName_addr);
-
+
// Build the function type: struct objc_selector *sel_registerName(uint8_t*)
-
+
// The below code would be "more correct," but in actuality what's required is uint8_t*
//Type *sel_type = StructType::get(m_module->getContext());
//Type *sel_ptr_type = PointerType::getUnqual(sel_type);
Type *sel_ptr_type = Type::getInt8PtrTy(m_module->getContext());
-
+
Type *type_array[1];
-
+
type_array[0] = llvm::Type::getInt8PtrTy(m_module->getContext());
-
+
ArrayRef<Type *> srN_arg_types(type_array, 1);
-
+
llvm::Type *srN_type = FunctionType::get(sel_ptr_type, srN_arg_types, false);
-
+
// Build the constant containing the pointer to the function
PointerType *srN_ptr_ty = PointerType::getUnqual(srN_type);
Constant *srN_addr_int = ConstantInt::get(m_intptr_ty, sel_registerName_addr, false);
m_sel_registerName = ConstantExpr::getIntToPtr(srN_addr_int, srN_ptr_ty);
}
-
+
Value *argument_array[1];
-
+
Constant *omvn_pointer = ConstantExpr::getBitCast(_objc_meth_var_name_, Type::getInt8PtrTy(m_module->getContext()));
-
+
argument_array[0] = omvn_pointer;
-
+
ArrayRef<Value *> srN_arguments(argument_array, 1);
-
- CallInst *srN_call = CallInst::Create(m_sel_registerName,
+
+ CallInst *srN_call = CallInst::Create(m_sel_registerName,
srN_arguments,
"sel_registerName",
selector_load);
-
+
// Replace the load with the call in all users
-
+
selector_load->replaceAllUsesWith(srN_call);
-
+
selector_load->eraseFromParent();
-
+
return true;
}
@@ -1178,25 +1164,25 @@ IRForTarget::RewriteObjCSelectors (BasicBlock &basic_block)
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
BasicBlock::iterator ii;
-
+
typedef SmallVector <Instruction*, 2> InstrList;
typedef InstrList::iterator InstrIterator;
-
+
InstrList selector_loads;
-
+
for (ii = basic_block.begin();
ii != basic_block.end();
++ii)
{
Instruction &inst = *ii;
-
+
if (LoadInst *load = dyn_cast<LoadInst>(&inst))
if (IsObjCSelectorRef(load->getPointerOperand()))
selector_loads.push_back(&inst);
}
-
+
InstrIterator iter;
-
+
for (iter = selector_loads.begin();
iter != selector_loads.end();
++iter)
@@ -1205,111 +1191,111 @@ IRForTarget::RewriteObjCSelectors (BasicBlock &basic_block)
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't change a static reference to an Objective-C selector to a dynamic reference\n");
-
+
if (log)
log->PutCString("Couldn't rewrite a reference to an Objective-C selector");
-
+
return false;
}
}
-
+
return true;
}
// This function does not report errors; its callers are responsible.
-bool
+bool
IRForTarget::RewritePersistentAlloc (llvm::Instruction *persistent_alloc)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
AllocaInst *alloc = dyn_cast<AllocaInst>(persistent_alloc);
-
+
MDNode *alloc_md = alloc->getMetadata("clang.decl.ptr");
if (!alloc_md || !alloc_md->getNumOperands())
return false;
-
+
ConstantInt *constant_int = dyn_cast<ConstantInt>(alloc_md->getOperand(0));
-
+
if (!constant_int)
return false;
-
+
// We attempt to register this as a new persistent variable with the DeclMap.
-
+
uintptr_t ptr = constant_int->getZExtValue();
-
+
clang::VarDecl *decl = reinterpret_cast<clang::VarDecl *>(ptr);
-
+
lldb_private::TypeFromParser result_decl_type (decl->getType().getAsOpaquePtr(),
&decl->getASTContext());
-
+
StringRef decl_name (decl->getName());
lldb_private::ConstString persistent_variable_name (decl_name.data(), decl_name.size());
if (!m_decl_map->AddPersistentVariable(decl, persistent_variable_name, result_decl_type, false, false))
return false;
-
+
GlobalVariable *persistent_global = new GlobalVariable((*m_module),
alloc->getType(),
false, /* not constant */
GlobalValue::ExternalLinkage,
NULL, /* no initializer */
alloc->getName().str().c_str());
-
+
// What we're going to do here is make believe this was a regular old external
// variable. That means we need to make the metadata valid.
-
+
NamedMDNode *named_metadata = m_module->getOrInsertNamedMetadata("clang.global.decl.ptrs");
-
+
llvm::Value* values[2];
values[0] = persistent_global;
values[1] = constant_int;
-
+
ArrayRef<llvm::Value*> value_ref(values, 2);
MDNode *persistent_global_md = MDNode::get(m_module->getContext(), value_ref);
named_metadata->addOperand(persistent_global_md);
-
+
// Now, since the variable is a pointer variable, we will drop in a load of that
// pointer variable.
-
+
LoadInst *persistent_load = new LoadInst (persistent_global, "", alloc);
-
+
if (log)
log->Printf("Replacing \"%s\" with \"%s\"",
PrintValue(alloc).c_str(),
PrintValue(persistent_load).c_str());
-
+
alloc->replaceAllUsesWith(persistent_load);
alloc->eraseFromParent();
-
+
return true;
}
-bool
+bool
IRForTarget::RewritePersistentAllocs(llvm::BasicBlock &basic_block)
{
if (!m_resolve_vars)
return true;
-
+
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
BasicBlock::iterator ii;
-
+
typedef SmallVector <Instruction*, 2> InstrList;
typedef InstrList::iterator InstrIterator;
-
+
InstrList pvar_allocs;
-
+
for (ii = basic_block.begin();
ii != basic_block.end();
++ii)
{
Instruction &inst = *ii;
-
+
if (AllocaInst *alloc = dyn_cast<AllocaInst>(&inst))
{
llvm::StringRef alloc_name = alloc->getName();
-
+
if (alloc_name.startswith("$") &&
!alloc_name.startswith("$__lldb"))
{
@@ -1317,20 +1303,20 @@ IRForTarget::RewritePersistentAllocs(llvm::BasicBlock &basic_block)
{
if (log)
log->Printf("Rejecting a numeric persistent variable.");
-
+
if (m_error_stream)
m_error_stream->Printf("Error [IRForTarget]: Names starting with $0, $1, ... are reserved for use as result names\n");
-
+
return false;
}
-
+
pvar_allocs.push_back(alloc);
}
}
}
-
+
InstrIterator iter;
-
+
for (iter = pvar_allocs.begin();
iter != pvar_allocs.end();
++iter)
@@ -1339,14 +1325,14 @@ IRForTarget::RewritePersistentAllocs(llvm::BasicBlock &basic_block)
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite the creation of a persistent variable\n");
-
+
if (log)
log->PutCString("Couldn't rewrite the creation of a persistent variable");
-
+
return false;
}
}
-
+
return true;
}
@@ -1355,14 +1341,14 @@ IRForTarget::MaterializeInitializer (uint8_t *data, Constant *initializer)
{
if (!initializer)
return true;
-
+
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (log && log->GetVerbose())
log->Printf(" MaterializeInitializer(%p, %s)", data, PrintValue(initializer).c_str());
-
+
Type *initializer_type = initializer->getType();
-
+
if (ConstantInt *int_initializer = dyn_cast<ConstantInt>(initializer))
{
memcpy (data, int_initializer->getValue().getRawData(), m_target_data->getTypeStoreSize(initializer_type));
@@ -1379,17 +1365,17 @@ IRForTarget::MaterializeInitializer (uint8_t *data, Constant *initializer)
{
ArrayType *array_initializer_type = array_initializer->getType();
Type *array_element_type = array_initializer_type->getElementType();
-
+
size_t element_size = m_target_data->getTypeAllocSize(array_element_type);
-
+
for (unsigned i = 0; i < array_initializer->getNumOperands(); ++i)
{
Value *operand_value = array_initializer->getOperand(i);
Constant *operand_constant = dyn_cast<Constant>(operand_value);
-
+
if (!operand_constant)
return false;
-
+
if (!MaterializeInitializer(data + (i * element_size), operand_constant))
return false;
}
@@ -1423,52 +1409,52 @@ IRForTarget::MaterializeInternalVariable (GlobalVariable *global_variable)
{
if (GlobalVariable::isExternalLinkage(global_variable->getLinkage()))
return false;
-
+
if (global_variable == m_reloc_placeholder)
return true;
-
+
uint64_t offset = m_data_allocator.GetStream().GetSize();
-
+
llvm::Type *variable_type = global_variable->getType();
-
+
Constant *initializer = global_variable->getInitializer();
-
+
llvm::Type *initializer_type = initializer->getType();
-
+
size_t size = m_target_data->getTypeAllocSize(initializer_type);
size_t align = m_target_data->getPrefTypeAlignment(initializer_type);
-
+
const size_t mask = (align - 1);
uint64_t aligned_offset = (offset + mask) & ~mask;
m_data_allocator.GetStream().PutNHex8(aligned_offset - offset, 0);
offset = aligned_offset;
-
+
lldb_private::DataBufferHeap data(size, '\0');
-
+
if (initializer)
if (!MaterializeInitializer(data.GetBytes(), initializer))
return false;
-
+
m_data_allocator.GetStream().Write(data.GetBytes(), data.GetByteSize());
-
+
Constant *new_pointer = BuildRelocation(variable_type, offset);
-
+
global_variable->replaceAllUsesWith(new_pointer);
global_variable->eraseFromParent();
-
+
return true;
}
// This function does not report errors; its callers are responsible.
-bool
+bool
IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (log)
log->Printf("MaybeHandleVariable (%s)", PrintValue(llvm_value_ptr).c_str());
-
+
if (ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(llvm_value_ptr))
{
switch (constant_expr->getOpcode())
@@ -1486,31 +1472,31 @@ IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr)
{
if (!GlobalValue::isExternalLinkage(global_variable->getLinkage()))
return MaterializeInternalVariable(global_variable);
-
+
clang::NamedDecl *named_decl = DeclForGlobal(global_variable);
-
+
if (!named_decl)
{
if (IsObjCSelectorRef(llvm_value_ptr))
return true;
-
+
if (!global_variable->hasExternalLinkage())
return true;
-
+
if (log)
log->Printf("Found global variable \"%s\" without metadata", global_variable->getName().str().c_str());
-
+
return false;
}
-
+
std::string name (named_decl->getName().str());
-
+
clang::ValueDecl *value_decl = dyn_cast<clang::ValueDecl>(named_decl);
if (value_decl == NULL)
return false;
lldb_private::ClangASTType clang_type(&value_decl->getASTContext(), value_decl->getType());
-
+
const Type *value_type = NULL;
if (name[0] == '$')
@@ -1531,25 +1517,25 @@ IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr)
{
value_type = global_variable->getType();
}
-
+
const uint64_t value_size = clang_type.GetByteSize();
- off_t value_alignment = (clang_type.GetTypeBitAlign() + 7ull) / 8ull;
-
+ lldb::offset_t value_alignment = (clang_type.GetTypeBitAlign() + 7ull) / 8ull;
+
if (log)
{
- log->Printf("Type of \"%s\" is [clang \"%s\", llvm \"%s\"] [size %" PRIu64 ", align %" PRId64 "]",
- name.c_str(),
+ log->Printf("Type of \"%s\" is [clang \"%s\", llvm \"%s\"] [size %" PRIu64 ", align %" PRIu64 "]",
+ name.c_str(),
clang_type.GetQualType().getAsString().c_str(),
PrintType(value_type).c_str(),
- value_size,
+ value_size,
value_alignment);
}
-
-
+
+
if (named_decl && !m_decl_map->AddValueToStruct(named_decl,
lldb_private::ConstString (name.c_str()),
llvm_value_ptr,
- value_size,
+ value_size,
value_alignment))
{
if (!global_variable->hasExternalLinkage())
@@ -1564,45 +1550,45 @@ IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr)
{
if (log)
log->Printf("Function pointers aren't handled right now");
-
+
return false;
}
-
+
return true;
}
// This function does not report errors; its callers are responsible.
bool
IRForTarget::HandleSymbol (Value *symbol)
-{
+{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
lldb_private::ConstString name(symbol->getName().str().c_str());
-
+
lldb::addr_t symbol_addr = m_decl_map->GetSymbolAddress (name, lldb::eSymbolTypeAny);
-
+
if (symbol_addr == LLDB_INVALID_ADDRESS)
{
if (log)
log->Printf ("Symbol \"%s\" had no address", name.GetCString());
-
+
return false;
}
if (log)
log->Printf("Found \"%s\" at 0x%" PRIx64, name.GetCString(), symbol_addr);
-
+
Type *symbol_type = symbol->getType();
-
+
Constant *symbol_addr_int = ConstantInt::get(m_intptr_ty, symbol_addr, false);
-
+
Value *symbol_addr_ptr = ConstantExpr::getIntToPtr(symbol_addr_int, symbol_type);
-
+
if (log)
log->Printf("Replacing %s with %s", PrintValue(symbol).c_str(), PrintValue(symbol_addr_ptr).c_str());
-
+
symbol->replaceAllUsesWith(symbol_addr_ptr);
-
+
return true;
}
@@ -1610,10 +1596,10 @@ bool
IRForTarget::MaybeHandleCallArguments (CallInst *Old)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (log)
log->Printf("MaybeHandleCallArguments(%s)", PrintValue(Old).c_str());
-
+
for (unsigned op_index = 0, num_ops = Old->getNumArgOperands();
op_index < num_ops;
++op_index)
@@ -1621,10 +1607,10 @@ IRForTarget::MaybeHandleCallArguments (CallInst *Old)
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite one of the arguments of a function call.\n");
-
+
return false;
}
-
+
return true;
}
@@ -1634,55 +1620,53 @@ IRForTarget::HandleObjCClass(Value *classlist_reference)
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
GlobalVariable *global_variable = dyn_cast<GlobalVariable>(classlist_reference);
-
+
if (!global_variable)
return false;
-
+
Constant *initializer = global_variable->getInitializer();
-
+
if (!initializer)
return false;
-
+
if (!initializer->hasName())
return false;
-
+
StringRef name(initializer->getName());
lldb_private::ConstString name_cstr(name.str().c_str());
lldb::addr_t class_ptr = m_decl_map->GetSymbolAddress(name_cstr, lldb::eSymbolTypeObjCClass);
-
+
if (log)
log->Printf("Found reference to Objective-C class %s (0x%llx)", name_cstr.AsCString(), (unsigned long long)class_ptr);
-
+
if (class_ptr == LLDB_INVALID_ADDRESS)
return false;
-
- if (global_variable->use_begin() == global_variable->use_end())
+
+ if (global_variable->use_empty())
return false;
-
+
SmallVector<LoadInst *, 2> load_instructions;
-
- for (Value::use_iterator i = global_variable->use_begin(), e = global_variable->use_end();
- i != e;
- ++i)
+
+ for (llvm::User *u : global_variable->users())
{
- if (LoadInst *load_instruction = dyn_cast<LoadInst>(*i))
+ if (LoadInst *load_instruction = dyn_cast<LoadInst>(u))
load_instructions.push_back(load_instruction);
}
-
+
if (load_instructions.empty())
return false;
-
+
Constant *class_addr = ConstantInt::get(m_intptr_ty, (uint64_t)class_ptr);
-
+
for (LoadInst *load_instruction : load_instructions)
{
Constant *class_bitcast = ConstantExpr::getIntToPtr(class_addr, load_instruction->getType());
-
+
load_instruction->replaceAllUsesWith(class_bitcast);
-
+
load_instruction->eraseFromParent();
}
-
+
return true;
}
@@ -1690,54 +1674,54 @@ bool
IRForTarget::RemoveCXAAtExit (BasicBlock &basic_block)
{
BasicBlock::iterator ii;
-
+
std::vector<CallInst *> calls_to_remove;
-
+
for (ii = basic_block.begin();
ii != basic_block.end();
++ii)
{
Instruction &inst = *ii;
-
+
CallInst *call = dyn_cast<CallInst>(&inst);
-
+
// MaybeHandleCallArguments handles error reporting; we are silent here
if (!call)
continue;
-
+
bool remove = false;
-
+
llvm::Function *func = call->getCalledFunction();
-
+
if (func && func->getName() == "__cxa_atexit")
remove = true;
-
+
llvm::Value *val = call->getCalledValue();
-
+
if (val && val->getName() == "__cxa_atexit")
remove = true;
-
+
if (remove)
calls_to_remove.push_back(call);
}
-
+
for (std::vector<CallInst *>::iterator ci = calls_to_remove.begin(), ce = calls_to_remove.end();
ci != ce;
++ci)
{
(*ci)->eraseFromParent();
}
-
+
return true;
}
bool
IRForTarget::ResolveCalls(BasicBlock &basic_block)
-{
+{
/////////////////////////////////////////////////////////////////////////
// Prepare the current basic block for execution in the remote process
//
-
+
BasicBlock::iterator ii;
for (ii = basic_block.begin();
@@ -1745,14 +1729,14 @@ IRForTarget::ResolveCalls(BasicBlock &basic_block)
++ii)
{
Instruction &inst = *ii;
-
+
CallInst *call = dyn_cast<CallInst>(&inst);
-
+
// MaybeHandleCallArguments handles error reporting; we are silent here
if (call && !MaybeHandleCallArguments(call))
return false;
}
-
+
return true;
}
@@ -1760,68 +1744,58 @@ bool
IRForTarget::ResolveExternals (Function &llvm_function)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
- for (Module::global_iterator global = m_module->global_begin(), end = m_module->global_end();
- global != end;
- ++global)
+
+ for (GlobalVariable &global_var : m_module->globals())
{
- if (!global)
- {
- if (m_error_stream)
- m_error_stream->Printf("Internal error [IRForTarget]: global variable is NULL");
-
- return false;
- }
-
- std::string global_name = (*global).getName().str();
-
+ std::string global_name = global_var.getName().str();
+
if (log)
- log->Printf("Examining %s, DeclForGlobalValue returns %p",
+ log->Printf("Examining %s, DeclForGlobalValue returns %p",
global_name.c_str(),
- DeclForGlobal(global));
-
+ static_cast<void*>(DeclForGlobal(&global_var)));
+
if (global_name.find("OBJC_IVAR") == 0)
{
- if (!HandleSymbol(global))
+ if (!HandleSymbol(&global_var))
{
if (m_error_stream)
m_error_stream->Printf("Error [IRForTarget]: Couldn't find Objective-C indirect ivar symbol %s\n", global_name.c_str());
-
+
return false;
}
}
else if (global_name.find("OBJC_CLASSLIST_REFERENCES_$") != global_name.npos)
{
- if (!HandleObjCClass(global))
+ if (!HandleObjCClass(&global_var))
{
if (m_error_stream)
m_error_stream->Printf("Error [IRForTarget]: Couldn't resolve the class for an Objective-C static method call\n");
-
+
return false;
}
}
else if (global_name.find("OBJC_CLASSLIST_SUP_REFS_$") != global_name.npos)
{
- if (!HandleObjCClass(global))
+ if (!HandleObjCClass(&global_var))
{
if (m_error_stream)
m_error_stream->Printf("Error [IRForTarget]: Couldn't resolve the class for an Objective-C static method call\n");
-
+
return false;
}
}
- else if (DeclForGlobal(global))
+ else if (DeclForGlobal(&global_var))
{
- if (!MaybeHandleVariable (global))
+ if (!MaybeHandleVariable (&global_var))
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite external variable %s\n", global_name.c_str());
-
+
return false;
}
}
}
-
+
return true;
}
@@ -1829,40 +1803,36 @@ bool
IRForTarget::ReplaceStrings ()
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
typedef std::map <GlobalVariable *, size_t> OffsetsTy;
-
+
OffsetsTy offsets;
-
- for (Module::global_iterator gi = m_module->global_begin(), ge = m_module->global_end();
- gi != ge;
- ++gi)
- {
- GlobalVariable *gv = gi;
-
- if (!gv->hasInitializer())
+
+ for (GlobalVariable &gv : m_module->globals())
+ {
+ if (!gv.hasInitializer())
continue;
-
- Constant *gc = gv->getInitializer();
-
+
+ Constant *gc = gv.getInitializer();
+
std::string str;
-
+
if (gc->isNullValue())
{
Type *gc_type = gc->getType();
-
+
ArrayType *gc_array_type = dyn_cast<ArrayType>(gc_type);
-
+
if (!gc_array_type)
continue;
-
+
Type *gc_element_type = gc_array_type->getElementType();
-
+
IntegerType *gc_integer_type = dyn_cast<IntegerType>(gc_element_type);
-
+
if (gc_integer_type->getBitWidth() != 8)
continue;
-
+
str = "";
}
else
@@ -1871,108 +1841,102 @@ IRForTarget::ReplaceStrings ()
if (!gc_array)
continue;
-
+
if (!gc_array->isCString())
continue;
-
+
if (log)
log->Printf("Found a GlobalVariable with string initializer %s", PrintValue(gc).c_str());
-
+
str = gc_array->getAsString();
}
-
- offsets[gv] = m_data_allocator.GetStream().GetSize();
-
+
+ offsets[&gv] = m_data_allocator.GetStream().GetSize();
+
m_data_allocator.GetStream().Write(str.c_str(), str.length() + 1);
}
-
+
Type *char_ptr_ty = Type::getInt8PtrTy(m_module->getContext());
-
+
for (OffsetsTy::iterator oi = offsets.begin(), oe = offsets.end();
oi != oe;
++oi)
{
GlobalVariable *gv = oi->first;
size_t offset = oi->second;
-
+
Constant *new_initializer = BuildRelocation(char_ptr_ty, offset);
-
+
if (log)
log->Printf("Replacing GV %s with %s", PrintValue(gv).c_str(), PrintValue(new_initializer).c_str());
-
- for (GlobalVariable::use_iterator ui = gv->use_begin(), ue = gv->use_end();
- ui != ue;
- ++ui)
+
+ for (llvm::User *u : gv->users())
{
if (log)
- log->Printf("Found use %s", PrintValue(*ui).c_str());
-
- ConstantExpr *const_expr = dyn_cast<ConstantExpr>(*ui);
- StoreInst *store_inst = dyn_cast<StoreInst>(*ui);
-
+ log->Printf("Found use %s", PrintValue(u).c_str());
+
+ ConstantExpr *const_expr = dyn_cast<ConstantExpr>(u);
+ StoreInst *store_inst = dyn_cast<StoreInst>(u);
+
if (const_expr)
{
if (const_expr->getOpcode() != Instruction::GetElementPtr)
{
if (log)
log->Printf("Use (%s) of string variable is not a GetElementPtr constant", PrintValue(const_expr).c_str());
-
+
return false;
}
-
+
Constant *bit_cast = ConstantExpr::getBitCast(new_initializer, const_expr->getOperand(0)->getType());
Constant *new_gep = const_expr->getWithOperandReplaced(0, bit_cast);
-
+
const_expr->replaceAllUsesWith(new_gep);
}
else if (store_inst)
{
Constant *bit_cast = ConstantExpr::getBitCast(new_initializer, store_inst->getValueOperand()->getType());
-
+
store_inst->setOperand(0, bit_cast);
}
else
{
if (log)
log->Printf("Use (%s) of string variable is neither a constant nor a store", PrintValue(const_expr).c_str());
-
+
return false;
}
}
-
+
gv->eraseFromParent();
}
-
+
return true;
}
-bool
+bool
IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
typedef SmallVector <Value*, 2> ConstantList;
typedef SmallVector <llvm::Instruction*, 2> UserList;
typedef ConstantList::iterator ConstantIterator;
typedef UserList::iterator UserIterator;
-
+
ConstantList static_constants;
UserList static_users;
-
+
for (BasicBlock::iterator ii = basic_block.begin(), ie = basic_block.end();
ii != ie;
++ii)
{
llvm::Instruction &inst = *ii;
-
- for (Instruction::op_iterator oi = inst.op_begin(), oe = inst.op_end();
- oi != oe;
- ++oi)
+
+ for (Value *operand_val : inst.operand_values())
{
- Value *operand_val = oi->get();
-
ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val);
-
+
if (operand_constant_fp/* && operand_constant_fp->getType()->isX86_FP80Ty()*/)
{
static_constants.push_back(operand_val);
@@ -1980,10 +1944,10 @@ IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block)
}
}
}
-
+
ConstantIterator constant_iter;
UserIterator user_iter;
-
+
for (constant_iter = static_constants.begin(), user_iter = static_users.begin();
constant_iter != static_constants.end();
++constant_iter, ++user_iter)
@@ -1992,17 +1956,17 @@ IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block)
llvm::Instruction *inst = *user_iter;
ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val);
-
+
if (operand_constant_fp)
{
Type *operand_type = operand_constant_fp->getType();
APFloat operand_apfloat = operand_constant_fp->getValueAPF();
APInt operand_apint = operand_apfloat.bitcastToAPInt();
-
+
const uint8_t* operand_raw_data = (const uint8_t*)operand_apint.getRawData();
size_t operand_data_size = operand_apint.getBitWidth() / 8;
-
+
if (log)
{
std::string s;
@@ -2015,16 +1979,16 @@ IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block)
ss << " ";
}
ss.flush();
-
- log->Printf("Found ConstantFP with size %zu and raw data %s", operand_data_size, s.c_str());
+
+ log->Printf("Found ConstantFP with size %" PRIu64 " and raw data %s", (uint64_t)operand_data_size, s.c_str());
}
-
+
lldb_private::DataBufferHeap data(operand_data_size, 0);
-
+
if (lldb::endian::InlHostByteOrder() != m_data_allocator.GetStream().GetByteOrder())
{
uint8_t *data_bytes = data.GetBytes();
-
+
for (size_t index = 0;
index < operand_data_size;
++index)
@@ -2036,77 +2000,72 @@ IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block)
{
memcpy(data.GetBytes(), operand_raw_data, operand_data_size);
}
-
+
uint64_t offset = m_data_allocator.GetStream().GetSize();
-
+
size_t align = m_target_data->getPrefTypeAlignment(operand_type);
-
+
const size_t mask = (align - 1);
uint64_t aligned_offset = (offset + mask) & ~mask;
m_data_allocator.GetStream().PutNHex8(aligned_offset - offset, 0);
- offset = aligned_offset;
-
+
m_data_allocator.GetStream().Write(data.GetBytes(), operand_data_size);
-
+
llvm::Type *fp_ptr_ty = operand_constant_fp->getType()->getPointerTo();
-
+
Constant *new_pointer = BuildRelocation(fp_ptr_ty, aligned_offset);
-
+
llvm::LoadInst *fp_load = new llvm::LoadInst(new_pointer, "fp_load", inst);
-
+
operand_constant_fp->replaceAllUsesWith(fp_load);
}
}
-
+
return true;
}
static bool isGuardVariableRef(Value *V)
{
Constant *Old = NULL;
-
+
if (!(Old = dyn_cast<Constant>(V)))
return false;
-
+
ConstantExpr *CE = NULL;
-
+
if ((CE = dyn_cast<ConstantExpr>(V)))
{
if (CE->getOpcode() != Instruction::BitCast)
return false;
-
+
Old = CE->getOperand(0);
}
-
+
GlobalVariable *GV = dyn_cast<GlobalVariable>(Old);
-
+
if (!GV || !GV->hasName() || !GV->getName().startswith("_ZGV"))
return false;
-
+
return true;
}
-void
+void
IRForTarget::TurnGuardLoadIntoZero(llvm::Instruction* guard_load)
{
Constant* zero(ConstantInt::get(Type::getInt8Ty(m_module->getContext()), 0, true));
- Value::use_iterator ui;
-
- for (ui = guard_load->use_begin();
- ui != guard_load->use_end();
- ++ui)
+ for (llvm::User *u : guard_load->users())
{
- if (isa<Constant>(*ui))
+ if (isa<Constant>(u))
{
// do nothing for the moment
}
else
{
- ui->replaceUsesOfWith(guard_load, zero);
+ u->replaceUsesOfWith(guard_load, zero);
}
}
-
+
guard_load->eraseFromParent();
}
@@ -2117,46 +2076,46 @@ static void ExciseGuardStore(Instruction* guard_store)
bool
IRForTarget::RemoveGuards(BasicBlock &basic_block)
-{
+{
///////////////////////////////////////////////////////
// Eliminate any reference to guard variables found.
//
-
+
BasicBlock::iterator ii;
-
+
typedef SmallVector <Instruction*, 2> InstrList;
typedef InstrList::iterator InstrIterator;
-
+
InstrList guard_loads;
InstrList guard_stores;
-
+
for (ii = basic_block.begin();
ii != basic_block.end();
++ii)
{
Instruction &inst = *ii;
-
+
if (LoadInst *load = dyn_cast<LoadInst>(&inst))
if (isGuardVariableRef(load->getPointerOperand()))
- guard_loads.push_back(&inst);
-
- if (StoreInst *store = dyn_cast<StoreInst>(&inst))
+ guard_loads.push_back(&inst);
+
+ if (StoreInst *store = dyn_cast<StoreInst>(&inst))
if (isGuardVariableRef(store->getPointerOperand()))
guard_stores.push_back(&inst);
}
-
+
InstrIterator iter;
-
+
for (iter = guard_loads.begin();
iter != guard_loads.end();
++iter)
TurnGuardLoadIntoZero(*iter);
-
+
for (iter = guard_stores.begin();
iter != guard_stores.end();
++iter)
ExciseGuardStore(*iter);
-
+
return true;
}
@@ -2168,27 +2127,23 @@ IRForTarget::UnfoldConstant(Constant *old_constant,
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
- Value::use_iterator ui;
-
SmallVector<User*, 16> users;
-
+
// We do this because the use list might change, invalidating our iterator.
// Much better to keep a work list ourselves.
- for (ui = old_constant->use_begin();
- ui != old_constant->use_end();
- ++ui)
- users.push_back(*ui);
-
+ for (llvm::User *u : old_constant->users())
+ users.push_back(u);
+
for (size_t i = 0;
i < users.size();
++i)
{
User *user = users[i];
-
+
if (Constant *constant = dyn_cast<Constant>(user))
{
// synthesize a new non-constant equivalent of the constant
-
+
if (ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(constant))
{
switch (constant_expr->getOpcode())
@@ -2198,20 +2153,20 @@ IRForTarget::UnfoldConstant(Constant *old_constant,
log->Printf("Unhandled constant expression type: \"%s\"", PrintValue(constant_expr).c_str());
return false;
case Instruction::BitCast:
- {
+ {
FunctionValueCache bit_cast_maker ([&value_maker, &entry_instruction_finder, old_constant, constant_expr] (llvm::Function *function)->llvm::Value* {
// UnaryExpr
// OperandList[0] is value
if (constant_expr->getOperand(0) != old_constant)
return constant_expr;
-
+
return new BitCastInst(value_maker.GetValue(function),
constant_expr->getType(),
"",
llvm::cast<Instruction>(entry_instruction_finder.GetValue(function)));
});
-
+
if (!UnfoldConstant(constant_expr, bit_cast_maker, entry_instruction_finder))
return false;
}
@@ -2221,35 +2176,35 @@ IRForTarget::UnfoldConstant(Constant *old_constant,
// GetElementPtrConstantExpr
// OperandList[0] is base
// OperandList[1]... are indices
-
+
FunctionValueCache get_element_pointer_maker ([&value_maker, &entry_instruction_finder, old_constant, constant_expr] (llvm::Function *function)->llvm::Value* {
Value *ptr = constant_expr->getOperand(0);
-
+
if (ptr == old_constant)
ptr = value_maker.GetValue(function);
-
+
std::vector<Value*> index_vector;
-
+
unsigned operand_index;
unsigned num_operands = constant_expr->getNumOperands();
-
+
for (operand_index = 1;
operand_index < num_operands;
++operand_index)
{
Value *operand = constant_expr->getOperand(operand_index);
-
+
if (operand == old_constant)
operand = value_maker.GetValue(function);
-
+
index_vector.push_back(operand);
}
-
+
ArrayRef <Value*> indices(index_vector);
-
+
return GetElementPtrInst::Create(ptr, indices, "", llvm::cast<Instruction>(entry_instruction_finder.GetValue(function)));
});
-
+
if (!UnfoldConstant(constant_expr, get_element_pointer_maker, entry_instruction_finder))
return false;
}
@@ -2277,162 +2232,162 @@ IRForTarget::UnfoldConstant(Constant *old_constant,
}
}
}
-
+
if (!isa<GlobalValue>(old_constant))
{
old_constant->destroyConstant();
}
-
+
return true;
}
-bool
+bool
IRForTarget::ReplaceVariables (Function &llvm_function)
{
if (!m_resolve_vars)
return true;
-
+
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
m_decl_map->DoStructLayout();
-
+
if (log)
log->Printf("Element arrangement:");
-
+
uint32_t num_elements;
uint32_t element_index;
-
+
size_t size;
- off_t alignment;
-
+ lldb::offset_t alignment;
+
if (!m_decl_map->GetStructInfo (num_elements, size, alignment))
return false;
-
+
Function::arg_iterator iter(llvm_function.getArgumentList().begin());
-
+
if (iter == llvm_function.getArgumentList().end())
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes no arguments (should take at least a struct pointer)");
-
+
return false;
}
-
+
Argument *argument = iter;
-
+
if (argument->getName().equals("this"))
{
++iter;
-
+
if (iter == llvm_function.getArgumentList().end())
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes only 'this' argument (should take a struct pointer too)");
-
+
return false;
}
-
+
argument = iter;
}
else if (argument->getName().equals("self"))
{
++iter;
-
+
if (iter == llvm_function.getArgumentList().end())
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes only 'self' argument (should take '_cmd' and a struct pointer too)");
-
+
return false;
}
-
+
if (!iter->getName().equals("_cmd"))
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes '%s' after 'self' argument (should take '_cmd')", iter->getName().str().c_str());
-
+
return false;
}
-
+
++iter;
-
+
if (iter == llvm_function.getArgumentList().end())
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes only 'self' and '_cmd' arguments (should take a struct pointer too)");
-
+
return false;
}
-
+
argument = iter;
}
-
+
if (!argument->getName().equals("$__lldb_arg"))
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes an argument named '%s' instead of the struct pointer", argument->getName().str().c_str());
-
+
return false;
}
-
+
if (log)
log->Printf("Arg: \"%s\"", PrintValue(argument).c_str());
-
+
BasicBlock &entry_block(llvm_function.getEntryBlock());
Instruction *FirstEntryInstruction(entry_block.getFirstNonPHIOrDbg());
-
+
if (!FirstEntryInstruction)
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find the first instruction in the wrapper for use in rewriting");
-
+
return false;
}
-
+
LLVMContext &context(m_module->getContext());
IntegerType *offset_type(Type::getInt32Ty(context));
-
+
if (!offset_type)
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't produce an offset type");
-
+
return false;
}
-
+
for (element_index = 0; element_index < num_elements; ++element_index)
{
const clang::NamedDecl *decl = NULL;
Value *value = NULL;
- off_t offset;
+ lldb::offset_t offset;
lldb_private::ConstString name;
-
+
if (!m_decl_map->GetStructElement (decl, value, offset, name, element_index))
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Structure information is incomplete");
-
+
return false;
}
-
+
if (log)
- log->Printf(" \"%s\" (\"%s\") placed at %" PRId64,
+ log->Printf(" \"%s\" (\"%s\") placed at %" PRIu64,
name.GetCString(),
decl->getNameAsString().c_str(),
offset);
-
+
if (value)
{
if (log)
log->Printf(" Replacing [%s]", PrintValue(value).c_str());
-
+
FunctionValueCache body_result_maker ([this, name, offset_type, offset, argument, value] (llvm::Function *function)->llvm::Value * {
// Per the comment at ASTResultSynthesizer::SynthesizeBodyResult, in cases where the result
// variable is an rvalue, we have to synthesize a dereference of the appropriate structure
// entry in order to produce the static variable that the AST thinks it is accessing.
-
+
llvm::Instruction *entry_instruction = llvm::cast<Instruction>(m_entry_instruction_finder.GetValue(function));
-
+
ConstantInt *offset_int(ConstantInt::get(offset_type, offset, true));
GetElementPtrInst *get_element_ptr = GetElementPtrInst::Create(argument,
offset_int,
@@ -2445,19 +2400,19 @@ IRForTarget::ReplaceVariables (Function &llvm_function)
value->getType()->getPointerTo(),
"",
entry_instruction);
-
+
LoadInst *load = new LoadInst(bit_cast, "", entry_instruction);
-
+
return load;
}
else
{
BitCastInst *bit_cast = new BitCastInst(get_element_ptr, value->getType(), "", entry_instruction);
-
+
return bit_cast;
}
- });
-
+ });
+
if (Constant *constant = dyn_cast<Constant>(value))
{
UnfoldConstant(constant, body_result_maker, m_entry_instruction_finder);
@@ -2472,15 +2427,15 @@ IRForTarget::ReplaceVariables (Function &llvm_function)
log->Printf("Unhandled non-constant type: \"%s\"", PrintValue(value).c_str());
return false;
}
-
+
if (GlobalVariable *var = dyn_cast<GlobalVariable>(value))
var->eraseFromParent();
}
}
-
+
if (log)
- log->Printf("Total structure [align %" PRId64 ", size %zu]", alignment, size);
-
+ log->Printf("Total structure [align %" PRId64 ", size %" PRIu64 "]", (int64_t)alignment, (uint64_t)size);
+
return true;
}
@@ -2488,29 +2443,29 @@ llvm::Constant *
IRForTarget::BuildRelocation(llvm::Type *type, uint64_t offset)
{
llvm::Constant *offset_int = ConstantInt::get(m_intptr_ty, offset);
-
+
llvm::Constant *offset_array[1];
-
+
offset_array[0] = offset_int;
-
+
llvm::ArrayRef<llvm::Constant *> offsets(offset_array, 1);
-
+
llvm::Constant *reloc_getelementptr = ConstantExpr::getGetElementPtr(m_reloc_placeholder, offsets);
llvm::Constant *reloc_getbitcast = ConstantExpr::getBitCast(reloc_getelementptr, type);
-
+
return reloc_getbitcast;
}
-bool
+bool
IRForTarget::CompleteDataAllocation ()
-{
+{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (!m_data_allocator.GetStream().GetSize())
return true;
-
+
lldb::addr_t allocation = m_data_allocator.Allocate();
-
+
if (log)
{
if (allocation)
@@ -2518,15 +2473,15 @@ IRForTarget::CompleteDataAllocation ()
else
log->Printf("Failed to allocate static data");
}
-
+
if (!allocation || allocation == LLDB_INVALID_ADDRESS)
return false;
-
+
Constant *relocated_addr = ConstantInt::get(m_intptr_ty, (uint64_t)allocation);
Constant *relocated_bitcast = ConstantExpr::getIntToPtr(relocated_addr, llvm::Type::getInt8PtrTy(m_module->getContext()));
-
+
m_reloc_placeholder->replaceAllUsesWith(relocated_bitcast);
-
+
m_reloc_placeholder->eraseFromParent();
return true;
@@ -2538,47 +2493,39 @@ IRForTarget::StripAllGVs (Module &llvm_module)
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
std::vector<GlobalVariable *> global_vars;
std::set<GlobalVariable *>erased_vars;
-
+
bool erased = true;
-
+
while (erased)
{
erased = false;
-
- for (Module::global_iterator gi = llvm_module.global_begin(), ge = llvm_module.global_end();
- gi != ge;
- ++gi)
+
+ for (GlobalVariable &global_var : llvm_module.globals())
{
- GlobalVariable *global_var = dyn_cast<GlobalVariable>(gi);
-
- global_var->removeDeadConstantUsers();
-
- if (global_var->use_empty())
+ global_var.removeDeadConstantUsers();
+
+ if (global_var.use_empty())
{
if (log)
log->Printf("Did remove %s",
- PrintValue(global_var).c_str());
- global_var->eraseFromParent();
+ PrintValue(&global_var).c_str());
+ global_var.eraseFromParent();
erased = true;
break;
}
}
}
-
- for (Module::global_iterator gi = llvm_module.global_begin(), ge = llvm_module.global_end();
- gi != ge;
- ++gi)
+
+ for (GlobalVariable &global_var : llvm_module.globals())
{
- GlobalVariable *global_var = dyn_cast<GlobalVariable>(gi);
+ GlobalValue::user_iterator ui = global_var.user_begin();
- GlobalValue::use_iterator ui = global_var->use_begin();
-
if (log)
log->Printf("Couldn't remove %s because of %s",
- PrintValue(global_var).c_str(),
+ PrintValue(&global_var).c_str(),
PrintValue(*ui).c_str());
}
-
+
return true;
}
@@ -2586,46 +2533,46 @@ bool
IRForTarget::runOnModule (Module &llvm_module)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
m_module = &llvm_module;
m_target_data.reset(new DataLayout(m_module));
m_intptr_ty = llvm::Type::getIntNTy(m_module->getContext(), m_target_data->getPointerSizeInBits());
-
+
if (log)
{
std::string s;
raw_string_ostream oss(s);
-
+
m_module->print(oss, NULL);
-
+
oss.flush();
-
+
log->Printf("Module as passed in to IRForTarget: \n\"%s\"", s.c_str());
}
-
+
Function* main_function = m_module->getFunction(StringRef(m_func_name.c_str()));
-
+
if (!main_function)
{
if (log)
log->Printf("Couldn't find \"%s()\" in the module", m_func_name.c_str());
-
+
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find wrapper '%s' in the module", m_func_name.c_str());
return false;
}
-
+
if (!FixFunctionLinkage (*main_function))
{
if (log)
log->Printf("Couldn't fix the linkage for the function");
-
+
return false;
}
-
+
llvm::Type *int8_ty = Type::getInt8Ty(m_module->getContext());
-
+
m_reloc_placeholder = new llvm::GlobalVariable((*m_module),
int8_ty,
false /* IsConstant */,
@@ -2639,14 +2586,14 @@ IRForTarget::runOnModule (Module &llvm_module)
////////////////////////////////////////////////////////////
// Replace $__lldb_expr_result with a persistent variable
//
-
+
if (!CreateResultVariable(*main_function))
{
if (log)
log->Printf("CreateResultVariable() failed");
-
+
// CreateResultVariable() reports its own errors, so we don't do so here
-
+
return false;
}
@@ -2654,25 +2601,25 @@ IRForTarget::runOnModule (Module &llvm_module)
{
std::string s;
raw_string_ostream oss(s);
-
+
m_module->print(oss, NULL);
-
+
oss.flush();
-
+
log->Printf("Module after creating the result variable: \n\"%s\"", s.c_str());
}
-
+
for (Module::iterator fi = m_module->begin(), fe = m_module->end();
fi != fe;
++fi)
{
llvm::Function *function = fi;
-
+
if (function->begin() == function->end())
continue;
-
+
Function::iterator bbi;
-
+
for (bbi = function->begin();
bbi != function->end();
++bbi)
@@ -2681,62 +2628,62 @@ IRForTarget::runOnModule (Module &llvm_module)
{
if (log)
log->Printf("RemoveGuards() failed");
-
+
// RemoveGuards() reports its own errors, so we don't do so here
-
+
return false;
}
-
+
if (!RewritePersistentAllocs(*bbi))
{
if (log)
log->Printf("RewritePersistentAllocs() failed");
-
+
// RewritePersistentAllocs() reports its own errors, so we don't do so here
-
+
return false;
}
-
+
if (!RemoveCXAAtExit(*bbi))
{
if (log)
log->Printf("RemoveCXAAtExit() failed");
-
+
// RemoveCXAAtExit() reports its own errors, so we don't do so here
-
+
return false;
}
}
}
-
+
///////////////////////////////////////////////////////////////////////////////
// Fix all Objective-C constant strings to use NSStringWithCString:encoding:
//
-
+
if (!RewriteObjCConstStrings())
{
if (log)
log->Printf("RewriteObjCConstStrings() failed");
-
+
// RewriteObjCConstStrings() reports its own errors, so we don't do so here
-
+
return false;
}
-
+
///////////////////////////////
// Resolve function pointers
//
-
+
if (!ResolveFunctionPointers(llvm_module))
{
if (log)
log->Printf("ResolveFunctionPointers() failed");
-
+
// ResolveFunctionPointers() reports its own errors, so we don't do so here
-
+
return false;
}
-
+
for (Module::iterator fi = m_module->begin(), fe = m_module->end();
fi != fe;
++fi)
@@ -2751,9 +2698,9 @@ IRForTarget::runOnModule (Module &llvm_module)
{
if (log)
log->Printf("RewriteObjCSelectors() failed");
-
+
// RewriteObjCSelectors() reports its own errors, so we don't do so here
-
+
return false;
}
}
@@ -2764,7 +2711,7 @@ IRForTarget::runOnModule (Module &llvm_module)
++fi)
{
llvm::Function *function = fi;
-
+
for (llvm::Function::iterator bbi = function->begin(), bbe = function->end();
bbi != bbe;
++bbi)
@@ -2773,81 +2720,81 @@ IRForTarget::runOnModule (Module &llvm_module)
{
if (log)
log->Printf("ResolveCalls() failed");
-
+
// ResolveCalls() reports its own errors, so we don't do so here
-
+
return false;
}
-
+
if (!ReplaceStaticLiterals(*bbi))
{
if (log)
log->Printf("ReplaceStaticLiterals() failed");
-
+
return false;
}
}
}
-
+
////////////////////////////////////////////////////////////////////////
// Run function-level passes that only make sense on the main function
//
-
+
if (!ResolveExternals(*main_function))
{
if (log)
log->Printf("ResolveExternals() failed");
-
+
// ResolveExternals() reports its own errors, so we don't do so here
-
+
return false;
}
-
+
if (!ReplaceVariables(*main_function))
{
if (log)
log->Printf("ReplaceVariables() failed");
-
+
// ReplaceVariables() reports its own errors, so we don't do so here
-
+
return false;
}
-
+
if (!ReplaceStrings())
{
if (log)
log->Printf("ReplaceStrings() failed");
-
+
return false;
}
-
+
if (!CompleteDataAllocation())
{
if (log)
log->Printf("CompleteDataAllocation() failed");
-
+
return false;
}
-
+
if (!StripAllGVs(llvm_module))
{
if (log)
log->Printf("StripAllGVs() failed");
}
-
+
if (log && log->GetVerbose())
{
std::string s;
raw_string_ostream oss(s);
-
+
m_module->print(oss, NULL);
-
+
oss.flush();
-
+
log->Printf("Module after preparing for execution: \n\"%s\"", s.c_str());
}
-
- return true;
+
+ return true;
}
void
diff --git a/source/Expression/IRInterpreter.cpp b/source/Expression/IRInterpreter.cpp
index 71ef8d6457bc..d11bdc1671b6 100644
--- a/source/Expression/IRInterpreter.cpp
+++ b/source/Expression/IRInterpreter.cpp
@@ -20,6 +20,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"
@@ -27,7 +28,7 @@
using namespace llvm;
-static std::string
+static std::string
PrintValue(const Value *value, bool truncate = false)
{
std::string s;
@@ -36,13 +37,13 @@ PrintValue(const Value *value, bool truncate = false)
rso.flush();
if (truncate)
s.resize(s.length() - 1);
-
+
size_t offset;
while ((offset = s.find('\n')) != s.npos)
s.erase(offset, 1);
while (s[0] == ' ' || s[0] == '\t')
s.erase(0, 1);
-
+
return s;
}
@@ -58,25 +59,48 @@ PrintType(const Type *type, bool truncate = false)
return s;
}
+static bool
+CanIgnoreCall (const CallInst *call)
+{
+ const llvm::Function *called_function = call->getCalledFunction();
+
+ if (!called_function)
+ return false;
+
+ if (called_function->isIntrinsic())
+ {
+ switch (called_function->getIntrinsicID())
+ {
+ default:
+ break;
+ case llvm::Intrinsic::dbg_declare:
+ case llvm::Intrinsic::dbg_value:
+ return true;
+ }
+ }
+
+ return false;
+}
+
class InterpreterStackFrame
{
public:
typedef std::map <const Value*, lldb::addr_t> ValueMap;
-
+
ValueMap m_values;
DataLayout &m_target_data;
lldb_private::IRMemoryMap &m_memory_map;
const BasicBlock *m_bb;
BasicBlock::const_iterator m_ii;
BasicBlock::const_iterator m_ie;
-
+
lldb::addr_t m_frame_process_address;
size_t m_frame_size;
lldb::addr_t m_stack_pointer;
-
+
lldb::ByteOrder m_byte_order;
size_t m_addr_byte_size;
-
+
InterpreterStackFrame (DataLayout &target_data,
lldb_private::IRMemoryMap &memory_map,
lldb::addr_t stack_frame_bottom,
@@ -86,41 +110,41 @@ public:
{
m_byte_order = (target_data.isLittleEndian() ? lldb::eByteOrderLittle : lldb::eByteOrderBig);
m_addr_byte_size = (target_data.getPointerSize(0));
-
+
m_frame_process_address = stack_frame_bottom;
m_frame_size = stack_frame_top - stack_frame_bottom;
m_stack_pointer = stack_frame_top;
}
-
+
~InterpreterStackFrame ()
{
}
-
+
void Jump (const BasicBlock *bb)
{
m_bb = bb;
m_ii = m_bb->begin();
m_ie = m_bb->end();
}
-
+
std::string SummarizeValue (const Value *value)
{
lldb_private::StreamString ss;
ss.Printf("%s", PrintValue(value).c_str());
-
+
ValueMap::iterator i = m_values.find(value);
if (i != m_values.end())
{
lldb::addr_t addr = i->second;
-
+
ss.Printf(" 0x%llx", (unsigned long long)addr);
}
-
+
return ss.GetString();
}
-
+
bool AssignToMatchType (lldb_private::Scalar &scalar, uint64_t u64value, Type *type)
{
size_t type_size = m_target_data.getTypeStoreSize(type);
@@ -142,36 +166,36 @@ public:
default:
return false;
}
-
+
return true;
}
-
+
bool EvaluateValue (lldb_private::Scalar &scalar, const Value *value, Module &module)
{
const Constant *constant = dyn_cast<Constant>(value);
-
+
if (constant)
{
APInt value_apint;
-
+
if (!ResolveConstantValue(value_apint, constant))
return false;
-
+
return AssignToMatchType(scalar, value_apint.getLimitedValue(), value->getType());
}
else
{
lldb::addr_t process_address = ResolveValue(value, module);
size_t value_size = m_target_data.getTypeStoreSize(value->getType());
-
+
lldb_private::DataExtractor value_extractor;
lldb_private::Error extract_error;
-
+
m_memory_map.GetMemoryData(value_extractor, process_address, value_size, extract_error);
-
+
if (!extract_error.Success())
return false;
-
+
lldb::offset_t offset = 0;
if (value_size == 1 || value_size == 2 || value_size == 4 || value_size == 8)
{
@@ -179,38 +203,38 @@ public:
return AssignToMatchType(scalar, u64value, value->getType());
}
}
-
+
return false;
}
-
+
bool AssignValue (const Value *value, lldb_private::Scalar &scalar, Module &module)
{
lldb::addr_t process_address = ResolveValue (value, module);
-
+
if (process_address == LLDB_INVALID_ADDRESS)
return false;
-
+
lldb_private::Scalar cast_scalar;
-
+
if (!AssignToMatchType(cast_scalar, scalar.GetRawBits64(0), value->getType()))
return false;
-
+
size_t value_byte_size = m_target_data.getTypeStoreSize(value->getType());
-
+
lldb_private::DataBufferHeap buf(value_byte_size, 0);
-
+
lldb_private::Error get_data_error;
-
+
if (!cast_scalar.GetAsMemoryData(buf.GetBytes(), buf.GetByteSize(), m_byte_order, get_data_error))
return false;
-
+
lldb_private::Error write_error;
-
+
m_memory_map.WriteMemory(process_address, buf.GetBytes(), buf.GetByteSize(), write_error);
-
+
return write_error.Success();
}
-
+
bool ResolveConstantValue (APInt &value, const Constant *constant)
{
switch (constant->getValueID())
@@ -246,27 +270,27 @@ public:
{
ConstantExpr::const_op_iterator op_cursor = constant_expr->op_begin();
ConstantExpr::const_op_iterator op_end = constant_expr->op_end();
-
+
Constant *base = dyn_cast<Constant>(*op_cursor);
-
+
if (!base)
return false;
-
+
if (!ResolveConstantValue(value, base))
return false;
-
+
op_cursor++;
-
+
if (op_cursor == op_end)
return true; // no offset to apply!
-
+
SmallVector <Value *, 8> indices (op_cursor, op_end);
-
+
uint64_t offset = m_target_data.getIndexedOffset(base->getType(), indices);
-
+
const bool is_signed = true;
value += APInt(value.getBitWidth(), offset, is_signed);
-
+
return true;
}
}
@@ -282,27 +306,27 @@ public:
}
return false;
}
-
+
bool MakeArgument(const Argument *value, uint64_t address)
{
lldb::addr_t data_address = Malloc(value->getType());
-
+
if (data_address == LLDB_INVALID_ADDRESS)
return false;
-
+
lldb_private::Error write_error;
-
+
m_memory_map.WritePointerToMemory(data_address, address, write_error);
-
+
if (!write_error.Success())
{
lldb_private::Error free_error;
m_memory_map.Free(data_address, free_error);
return false;
}
-
+
m_values[value] = data_address;
-
+
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (log)
@@ -311,75 +335,75 @@ public:
log->Printf(" Data region : %llx", (unsigned long long)address);
log->Printf(" Ref region : %llx", (unsigned long long)data_address);
}
-
+
return true;
}
-
+
bool ResolveConstant (lldb::addr_t process_address, const Constant *constant)
{
APInt resolved_value;
-
+
if (!ResolveConstantValue(resolved_value, constant))
return false;
-
+
lldb_private::StreamString buffer (lldb_private::Stream::eBinary,
m_memory_map.GetAddressByteSize(),
m_memory_map.GetByteOrder());
-
+
size_t constant_size = m_target_data.getTypeStoreSize(constant->getType());
-
+
const uint64_t *raw_data = resolved_value.getRawData();
-
+
buffer.PutRawBytes(raw_data, constant_size, lldb::endian::InlHostByteOrder());
-
+
lldb_private::Error write_error;
-
+
m_memory_map.WriteMemory(process_address, (const uint8_t*)buffer.GetData(), constant_size, write_error);
-
+
return write_error.Success();
}
-
+
lldb::addr_t Malloc (size_t size, uint8_t byte_alignment)
{
lldb::addr_t ret = m_stack_pointer;
-
+
ret -= size;
ret -= (ret % byte_alignment);
-
+
if (ret < m_frame_process_address)
return LLDB_INVALID_ADDRESS;
-
+
m_stack_pointer = ret;
return ret;
}
-
+
lldb::addr_t MallocPointer ()
{
return Malloc(m_target_data.getPointerSize(), m_target_data.getPointerPrefAlignment());
}
-
+
lldb::addr_t Malloc (llvm::Type *type)
{
lldb_private::Error alloc_error;
-
+
return Malloc(m_target_data.getTypeAllocSize(type), m_target_data.getPrefTypeAlignment(type));
}
-
+
std::string PrintData (lldb::addr_t addr, llvm::Type *type)
{
size_t length = m_target_data.getTypeStoreSize(type);
-
+
lldb_private::DataBufferHeap buf(length, 0);
-
+
lldb_private::Error read_error;
-
+
m_memory_map.ReadMemory(buf.GetBytes(), addr, length, read_error);
-
+
if (!read_error.Success())
return std::string("<couldn't read data>");
-
+
lldb_private::StreamString ss;
-
+
for (size_t i = 0; i < length; i++)
{
if ((!(i & 0xf)) && i)
@@ -387,21 +411,21 @@ public:
else
ss.Printf("%02hhx ", buf.GetBytes()[i]);
}
-
+
return ss.GetString();
}
-
+
lldb::addr_t ResolveValue (const Value *value, Module &module)
{
ValueMap::iterator i = m_values.find(value);
-
+
if (i != m_values.end())
return i->second;
-
+
// Fall back and allocate space [allocation type Alloca]
-
+
lldb::addr_t data_address = Malloc(value->getType());
-
+
if (const Constant *constant = dyn_cast<Constant>(value))
{
if (!ResolveConstant (data_address, constant))
@@ -411,7 +435,7 @@ public:
return LLDB_INVALID_ADDRESS;
}
}
-
+
m_values[value] = data_address;
return data_address;
}
@@ -434,9 +458,9 @@ IRInterpreter::CanInterpret (llvm::Module &module,
lldb_private::Error &error)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
bool saw_function_with_body = false;
-
+
for (Module::iterator fi = module.begin(), fe = module.end();
fi != fe;
++fi)
@@ -448,7 +472,7 @@ IRInterpreter::CanInterpret (llvm::Module &module,
saw_function_with_body = true;
}
}
-
+
for (Function::iterator bbi = function.begin(), bbe = function.end();
bbi != bbe;
++bbi)
@@ -471,26 +495,48 @@ IRInterpreter::CanInterpret (llvm::Module &module,
case Instruction::Alloca:
case Instruction::BitCast:
case Instruction::Br:
+ break;
+ case Instruction::Call:
+ {
+ CallInst *call_inst = dyn_cast<CallInst>(ii);
+
+ if (!call_inst)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ if (!CanIgnoreCall(call_inst))
+ {
+ if (log)
+ log->Printf("Unsupported instruction: %s", PrintValue(ii).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(unsupported_opcode_error);
+ return false;
+ }
+ }
+ break;
case Instruction::GetElementPtr:
break;
case Instruction::ICmp:
{
ICmpInst *icmp_inst = dyn_cast<ICmpInst>(ii);
-
+
if (!icmp_inst)
{
error.SetErrorToGenericError();
error.SetErrorString(interpreter_internal_error);
return false;
}
-
+
switch (icmp_inst->getPredicate())
{
default:
{
if (log)
log->Printf("Unsupported ICmp predicate: %s", PrintValue(ii).c_str());
-
+
error.SetErrorToGenericError();
error.SetErrorString(unsupported_opcode_error);
return false;
@@ -531,14 +577,14 @@ IRInterpreter::CanInterpret (llvm::Module &module,
case Instruction::ZExt:
break;
}
-
+
for (int oi = 0, oe = ii->getNumOperands();
oi != oe;
++oi)
{
Value *operand = ii->getOperand(oi);
Type *operand_type = operand->getType();
-
+
switch (operand_type->getTypeID())
{
default:
@@ -553,9 +599,9 @@ IRInterpreter::CanInterpret (llvm::Module &module,
}
}
}
-
+
}
-
+
return true;}
bool
@@ -568,60 +614,83 @@ IRInterpreter::Interpret (llvm::Module &module,
lldb::addr_t stack_frame_top)
{
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (log)
{
std::string s;
raw_string_ostream oss(s);
-
+
module.print(oss, NULL);
-
+
oss.flush();
-
+
log->Printf("Module as passed in to IRInterpreter::Interpret: \n\"%s\"", s.c_str());
}
-
+
DataLayout data_layout(&module);
-
+
InterpreterStackFrame frame(data_layout, memory_map, stack_frame_bottom, stack_frame_top);
-
+
if (frame.m_frame_process_address == LLDB_INVALID_ADDRESS)
{
error.SetErrorString("Couldn't allocate stack frame");
}
-
+
int arg_index = 0;
-
+
for (llvm::Function::arg_iterator ai = function.arg_begin(), ae = function.arg_end();
ai != ae;
++ai, ++arg_index)
{
- if (args.size() < arg_index)
+ if (args.size() < static_cast<size_t>(arg_index))
{
error.SetErrorString ("Not enough arguments passed in to function");
return false;
}
-
+
lldb::addr_t ptr = args[arg_index];
frame.MakeArgument(ai, ptr);
}
-
+
uint32_t num_insts = 0;
-
+
frame.Jump(function.begin());
-
+
while (frame.m_ii != frame.m_ie && (++num_insts < 4096))
{
const Instruction *inst = frame.m_ii;
-
+
if (log)
log->Printf("Interpreting %s", PrintValue(inst).c_str());
-
+
switch (inst->getOpcode())
{
default:
break;
+ case Instruction::Call:
+ {
+ const CallInst *call_inst = dyn_cast<CallInst>(inst);
+
+ if (!call_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns %s, but instruction is not a CallInst", inst->getOpcodeName());
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ if (!CanIgnoreCall(call_inst))
+ {
+ if (log)
+ log->Printf("The interpreter shouldn't have accepted %s", PrintValue(call_inst).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+ }
+ break;
case Instruction::Add:
case Instruction::Sub:
case Instruction::Mul:
@@ -637,7 +706,7 @@ IRInterpreter::Interpret (llvm::Module &module,
case Instruction::Xor:
{
const BinaryOperator *bin_op = dyn_cast<BinaryOperator>(inst);
-
+
if (!bin_op)
{
if (log)
@@ -646,13 +715,13 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(interpreter_internal_error);
return false;
}
-
+
Value *lhs = inst->getOperand(0);
Value *rhs = inst->getOperand(1);
-
+
lldb_private::Scalar L;
lldb_private::Scalar R;
-
+
if (!frame.EvaluateValue(L, lhs, module))
{
if (log)
@@ -661,7 +730,7 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
if (!frame.EvaluateValue(R, rhs, module))
{
if (log)
@@ -670,9 +739,9 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
lldb_private::Scalar result;
-
+
switch (inst->getOpcode())
{
default:
@@ -722,9 +791,9 @@ IRInterpreter::Interpret (llvm::Module &module,
result = L ^ R;
break;
}
-
+
frame.AssignValue(inst, result, module);
-
+
if (log)
{
log->Printf("Interpreted a %s", inst->getOpcodeName());
@@ -737,7 +806,7 @@ IRInterpreter::Interpret (llvm::Module &module,
case Instruction::Alloca:
{
const AllocaInst *alloca_inst = dyn_cast<AllocaInst>(inst);
-
+
if (!alloca_inst)
{
if (log)
@@ -746,7 +815,7 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(interpreter_internal_error);
return false;
}
-
+
if (alloca_inst->isArrayAllocation())
{
if (log)
@@ -755,17 +824,17 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(unsupported_opcode_error);
return false;
}
-
+
// The semantics of Alloca are:
// Create a region R of virtual memory of type T, backed by a data buffer
// Create a region P of virtual memory of type T*, backed by a data buffer
// Write the virtual address of R into P
-
+
Type *T = alloca_inst->getAllocatedType();
Type *Tptr = alloca_inst->getType();
-
+
lldb::addr_t R = frame.Malloc(T);
-
+
if (R == LLDB_INVALID_ADDRESS)
{
if (log)
@@ -774,9 +843,9 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(memory_allocation_error);
return false;
}
-
+
lldb::addr_t P = frame.Malloc(Tptr);
-
+
if (P == LLDB_INVALID_ADDRESS)
{
if (log)
@@ -785,11 +854,11 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(memory_allocation_error);
return false;
}
-
+
lldb_private::Error write_error;
-
+
memory_map.WritePointerToMemory(P, R, write_error);
-
+
if (!write_error.Success())
{
if (log)
@@ -801,9 +870,9 @@ IRInterpreter::Interpret (llvm::Module &module,
memory_map.Free(R, free_error);
return false;
}
-
+
frame.m_values[alloca_inst] = P;
-
+
if (log)
{
log->Printf("Interpreted an AllocaInst");
@@ -816,7 +885,7 @@ IRInterpreter::Interpret (llvm::Module &module,
case Instruction::ZExt:
{
const CastInst *cast_inst = dyn_cast<CastInst>(inst);
-
+
if (!cast_inst)
{
if (log)
@@ -825,11 +894,11 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(interpreter_internal_error);
return false;
}
-
+
Value *source = cast_inst->getOperand(0);
-
+
lldb_private::Scalar S;
-
+
if (!frame.EvaluateValue(S, source, module))
{
if (log)
@@ -838,14 +907,14 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
frame.AssignValue(inst, S, module);
}
break;
case Instruction::SExt:
{
const CastInst *cast_inst = dyn_cast<CastInst>(inst);
-
+
if (!cast_inst)
{
if (log)
@@ -854,11 +923,11 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(interpreter_internal_error);
return false;
}
-
+
Value *source = cast_inst->getOperand(0);
-
+
lldb_private::Scalar S;
-
+
if (!frame.EvaluateValue(S, source, module))
{
if (log)
@@ -867,18 +936,18 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
S.MakeSigned();
-
+
lldb_private::Scalar S_signextend(S.SLongLong());
-
+
frame.AssignValue(inst, S_signextend, module);
}
break;
case Instruction::Br:
{
const BranchInst *br_inst = dyn_cast<BranchInst>(inst);
-
+
if (!br_inst)
{
if (log)
@@ -887,13 +956,13 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(interpreter_internal_error);
return false;
}
-
+
if (br_inst->isConditional())
{
Value *condition = br_inst->getCondition();
-
+
lldb_private::Scalar C;
-
+
if (!frame.EvaluateValue(C, condition, module))
{
if (log)
@@ -902,12 +971,12 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
if (C.GetRawBits64(0))
frame.Jump(br_inst->getSuccessor(0));
else
frame.Jump(br_inst->getSuccessor(1));
-
+
if (log)
{
log->Printf("Interpreted a BrInst with a condition");
@@ -917,7 +986,7 @@ IRInterpreter::Interpret (llvm::Module &module,
else
{
frame.Jump(br_inst->getSuccessor(0));
-
+
if (log)
{
log->Printf("Interpreted a BrInst with no condition");
@@ -928,7 +997,7 @@ IRInterpreter::Interpret (llvm::Module &module,
case Instruction::GetElementPtr:
{
const GetElementPtrInst *gep_inst = dyn_cast<GetElementPtrInst>(inst);
-
+
if (!gep_inst)
{
if (log)
@@ -937,12 +1006,12 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(interpreter_internal_error);
return false;
}
-
+
const Value *pointer_operand = gep_inst->getPointerOperand();
Type *pointer_type = pointer_operand->getType();
-
+
lldb_private::Scalar P;
-
+
if (!frame.EvaluateValue(P, pointer_operand, module))
{
if (log)
@@ -951,25 +1020,25 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
typedef SmallVector <Value *, 8> IndexVector;
typedef IndexVector::iterator IndexIterator;
-
+
SmallVector <Value *, 8> indices (gep_inst->idx_begin(),
gep_inst->idx_end());
-
+
SmallVector <Value *, 8> const_indices;
-
+
for (IndexIterator ii = indices.begin(), ie = indices.end();
ii != ie;
++ii)
{
ConstantInt *constant_index = dyn_cast<ConstantInt>(*ii);
-
+
if (!constant_index)
{
lldb_private::Scalar I;
-
+
if (!frame.EvaluateValue(I, *ii, module))
{
if (log)
@@ -978,22 +1047,22 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
if (log)
log->Printf("Evaluated constant index %s as %llu", PrintValue(*ii).c_str(), I.ULongLong(LLDB_INVALID_ADDRESS));
-
+
constant_index = cast<ConstantInt>(ConstantInt::get((*ii)->getType(), I.ULongLong(LLDB_INVALID_ADDRESS)));
}
-
+
const_indices.push_back(constant_index);
}
-
+
uint64_t offset = data_layout.getIndexedOffset(pointer_type, const_indices);
-
+
lldb_private::Scalar Poffset = P + offset;
-
+
frame.AssignValue(inst, Poffset, module);
-
+
if (log)
{
log->Printf("Interpreted a GetElementPtrInst");
@@ -1005,7 +1074,7 @@ IRInterpreter::Interpret (llvm::Module &module,
case Instruction::ICmp:
{
const ICmpInst *icmp_inst = dyn_cast<ICmpInst>(inst);
-
+
if (!icmp_inst)
{
if (log)
@@ -1014,15 +1083,15 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(interpreter_internal_error);
return false;
}
-
+
CmpInst::Predicate predicate = icmp_inst->getPredicate();
-
+
Value *lhs = inst->getOperand(0);
Value *rhs = inst->getOperand(1);
-
+
lldb_private::Scalar L;
lldb_private::Scalar R;
-
+
if (!frame.EvaluateValue(L, lhs, module))
{
if (log)
@@ -1031,7 +1100,7 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
if (!frame.EvaluateValue(R, rhs, module))
{
if (log)
@@ -1040,9 +1109,9 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
lldb_private::Scalar result;
-
+
switch (predicate)
{
default:
@@ -1086,9 +1155,9 @@ IRInterpreter::Interpret (llvm::Module &module,
result = (L <= R);
break;
}
-
+
frame.AssignValue(inst, result, module);
-
+
if (log)
{
log->Printf("Interpreted an ICmpInst");
@@ -1101,7 +1170,7 @@ IRInterpreter::Interpret (llvm::Module &module,
case Instruction::IntToPtr:
{
const IntToPtrInst *int_to_ptr_inst = dyn_cast<IntToPtrInst>(inst);
-
+
if (!int_to_ptr_inst)
{
if (log)
@@ -1110,11 +1179,11 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(interpreter_internal_error);
return false;
}
-
+
Value *src_operand = int_to_ptr_inst->getOperand(0);
-
+
lldb_private::Scalar I;
-
+
if (!frame.EvaluateValue(I, src_operand, module))
{
if (log)
@@ -1123,9 +1192,9 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
frame.AssignValue(inst, I, module);
-
+
if (log)
{
log->Printf("Interpreted an IntToPtr");
@@ -1137,7 +1206,7 @@ IRInterpreter::Interpret (llvm::Module &module,
case Instruction::PtrToInt:
{
const PtrToIntInst *ptr_to_int_inst = dyn_cast<PtrToIntInst>(inst);
-
+
if (!ptr_to_int_inst)
{
if (log)
@@ -1146,11 +1215,11 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(interpreter_internal_error);
return false;
}
-
+
Value *src_operand = ptr_to_int_inst->getOperand(0);
-
+
lldb_private::Scalar I;
-
+
if (!frame.EvaluateValue(I, src_operand, module))
{
if (log)
@@ -1159,9 +1228,9 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
frame.AssignValue(inst, I, module);
-
+
if (log)
{
log->Printf("Interpreted a PtrToInt");
@@ -1173,7 +1242,7 @@ IRInterpreter::Interpret (llvm::Module &module,
case Instruction::Trunc:
{
const TruncInst *trunc_inst = dyn_cast<TruncInst>(inst);
-
+
if (!trunc_inst)
{
if (log)
@@ -1182,11 +1251,11 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(interpreter_internal_error);
return false;
}
-
+
Value *src_operand = trunc_inst->getOperand(0);
-
+
lldb_private::Scalar I;
-
+
if (!frame.EvaluateValue(I, src_operand, module))
{
if (log)
@@ -1195,9 +1264,9 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
frame.AssignValue(inst, I, module);
-
+
if (log)
{
log->Printf("Interpreted a Trunc");
@@ -1209,7 +1278,7 @@ IRInterpreter::Interpret (llvm::Module &module,
case Instruction::Load:
{
const LoadInst *load_inst = dyn_cast<LoadInst>(inst);
-
+
if (!load_inst)
{
if (log)
@@ -1218,15 +1287,15 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(interpreter_internal_error);
return false;
}
-
+
// The semantics of Load are:
// Create a region D that will contain the loaded data
// Resolve the region P containing a pointer
// Dereference P to get the region R that the data should be loaded from
// Transfer a unit of type type(D) from R to D
-
+
const Value *pointer_operand = load_inst->getPointerOperand();
-
+
Type *pointer_ty = pointer_operand->getType();
PointerType *pointer_ptr_ty = dyn_cast<PointerType>(pointer_ty);
if (!pointer_ptr_ty)
@@ -1238,10 +1307,10 @@ IRInterpreter::Interpret (llvm::Module &module,
return false;
}
Type *target_ty = pointer_ptr_ty->getElementType();
-
+
lldb::addr_t D = frame.ResolveValue(load_inst, module);
lldb::addr_t P = frame.ResolveValue(pointer_operand, module);
-
+
if (D == LLDB_INVALID_ADDRESS)
{
if (log)
@@ -1250,7 +1319,7 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
if (P == LLDB_INVALID_ADDRESS)
{
if (log)
@@ -1259,11 +1328,11 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
lldb::addr_t R;
lldb_private::Error read_error;
memory_map.ReadPointerFromMemory(&R, P, read_error);
-
+
if (!read_error.Success())
{
if (log)
@@ -1272,10 +1341,10 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(memory_read_error);
return false;
}
-
+
size_t target_size = data_layout.getTypeStoreSize(target_ty);
lldb_private::DataBufferHeap buffer(target_size, 0);
-
+
read_error.Clear();
memory_map.ReadMemory(buffer.GetBytes(), R, buffer.GetByteSize(), read_error);
if (!read_error.Success())
@@ -1286,7 +1355,7 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(memory_read_error);
return false;
}
-
+
lldb_private::Error write_error;
memory_map.WriteMemory(D, buffer.GetBytes(), buffer.GetByteSize(), write_error);
if (!write_error.Success())
@@ -1297,7 +1366,7 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(memory_read_error);
return false;
}
-
+
if (log)
{
log->Printf("Interpreted a LoadInst");
@@ -1314,7 +1383,7 @@ IRInterpreter::Interpret (llvm::Module &module,
case Instruction::Store:
{
const StoreInst *store_inst = dyn_cast<StoreInst>(inst);
-
+
if (!store_inst)
{
if (log)
@@ -1323,25 +1392,25 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(interpreter_internal_error);
return false;
}
-
+
// The semantics of Store are:
// Resolve the region D containing the data to be stored
// Resolve the region P containing a pointer
// Dereference P to get the region R that the data should be stored in
// Transfer a unit of type type(D) from D to R
-
+
const Value *value_operand = store_inst->getValueOperand();
const Value *pointer_operand = store_inst->getPointerOperand();
-
+
Type *pointer_ty = pointer_operand->getType();
PointerType *pointer_ptr_ty = dyn_cast<PointerType>(pointer_ty);
if (!pointer_ptr_ty)
return false;
Type *target_ty = pointer_ptr_ty->getElementType();
-
+
lldb::addr_t D = frame.ResolveValue(value_operand, module);
lldb::addr_t P = frame.ResolveValue(pointer_operand, module);
-
+
if (D == LLDB_INVALID_ADDRESS)
{
if (log)
@@ -1350,7 +1419,7 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
if (P == LLDB_INVALID_ADDRESS)
{
if (log)
@@ -1359,11 +1428,11 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(bad_value_error);
return false;
}
-
+
lldb::addr_t R;
lldb_private::Error read_error;
memory_map.ReadPointerFromMemory(&R, P, read_error);
-
+
if (!read_error.Success())
{
if (log)
@@ -1372,10 +1441,10 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(memory_read_error);
return false;
}
-
+
size_t target_size = data_layout.getTypeStoreSize(target_ty);
lldb_private::DataBufferHeap buffer(target_size, 0);
-
+
read_error.Clear();
memory_map.ReadMemory(buffer.GetBytes(), D, buffer.GetByteSize(), read_error);
if (!read_error.Success())
@@ -1386,7 +1455,7 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(memory_read_error);
return false;
}
-
+
lldb_private::Error write_error;
memory_map.WriteMemory(R, buffer.GetBytes(), buffer.GetByteSize(), write_error);
if (!write_error.Success())
@@ -1397,7 +1466,7 @@ IRInterpreter::Interpret (llvm::Module &module,
error.SetErrorString(memory_write_error);
return false;
}
-
+
if (log)
{
log->Printf("Interpreted a StoreInst");
@@ -1408,16 +1477,16 @@ IRInterpreter::Interpret (llvm::Module &module,
}
break;
}
-
+
++frame.m_ii;
}
-
+
if (num_insts >= 4096)
{
error.SetErrorToGenericError();
error.SetErrorString(infinite_loop_error);
return false;
}
-
+
return false;
}
diff --git a/source/Expression/IRMemoryMap.cpp b/source/Expression/IRMemoryMap.cpp
index 53f74aebfed1..a4fe7a968379 100644
--- a/source/Expression/IRMemoryMap.cpp
+++ b/source/Expression/IRMemoryMap.cpp
@@ -28,11 +28,11 @@ IRMemoryMap::IRMemoryMap (lldb::TargetSP target_sp) :
IRMemoryMap::~IRMemoryMap ()
{
lldb::ProcessSP process_sp = m_process_wp.lock();
-
+
if (process_sp)
{
AllocationMap::iterator iter;
-
+
Error err;
while ((iter = m_allocations.begin()) != m_allocations.end())
@@ -51,54 +51,32 @@ IRMemoryMap::FindSpace (size_t size)
{
lldb::TargetSP target_sp = m_target_wp.lock();
lldb::ProcessSP process_sp = m_process_wp.lock();
-
+
lldb::addr_t ret = LLDB_INVALID_ADDRESS;
-
+ if (size == 0)
+ return ret;
+
if (process_sp && process_sp->CanJIT() && process_sp->IsAlive())
{
Error alloc_error;
-
+
ret = process_sp->AllocateMemory(size, lldb::ePermissionsReadable | lldb::ePermissionsWritable, alloc_error);
-
+
if (!alloc_error.Success())
return LLDB_INVALID_ADDRESS;
else
return ret;
}
-
- for (int iterations = 0; iterations < 16; ++iterations)
+
+ ret = 0;
+ if (!m_allocations.empty())
{
- lldb::addr_t candidate = LLDB_INVALID_ADDRESS;
-
- switch (target_sp->GetArchitecture().GetAddressByteSize())
- {
- case 4:
- {
- uint32_t random_data = rand();
- candidate = random_data;
- candidate &= ~0xfffull;
- break;
- }
- case 8:
- {
- uint32_t random_low = rand();
- uint32_t random_high = rand();
- candidate = random_high;
- candidate <<= 32ull;
- candidate |= random_low;
- candidate &= ~0xfffull;
- break;
- }
- }
-
- if (IntersectsAllocation(candidate, size))
- continue;
-
- ret = candidate;
-
- return ret;
+ auto back = m_allocations.rbegin();
+ lldb::addr_t addr = back->first;
+ size_t alloc_size = back->second.m_size;
+ ret = llvm::RoundUpToAlignment(addr+alloc_size, 4096);
}
-
+
return ret;
}
@@ -107,9 +85,9 @@ IRMemoryMap::FindAllocation (lldb::addr_t addr, size_t size)
{
if (addr == LLDB_INVALID_ADDRESS)
return m_allocations.end();
-
+
AllocationMap::iterator iter = m_allocations.lower_bound (addr);
-
+
if (iter == m_allocations.end() ||
iter->first > addr)
{
@@ -117,54 +95,69 @@ IRMemoryMap::FindAllocation (lldb::addr_t addr, size_t size)
return m_allocations.end();
iter--;
}
-
+
if (iter->first <= addr && iter->first + iter->second.m_size >= addr + size)
return iter;
-
+
return m_allocations.end();
}
bool
-IRMemoryMap::IntersectsAllocation (lldb::addr_t addr, size_t size)
+IRMemoryMap::IntersectsAllocation (lldb::addr_t addr, size_t size) const
{
if (addr == LLDB_INVALID_ADDRESS)
return false;
-
- AllocationMap::iterator iter = m_allocations.lower_bound (addr);
-
- if (iter == m_allocations.end() ||
- iter->first > addr)
- {
- if (iter == m_allocations.begin())
- return false;
-
- iter--;
+
+ AllocationMap::const_iterator iter = m_allocations.lower_bound (addr);
+
+ // Since we only know that the returned interval begins at a location greater than or
+ // equal to where the given interval begins, it's possible that the given interval
+ // intersects either the returned interval or the previous interval. Thus, we need to
+ // check both. Note that we only need to check these two intervals. Since all intervals
+ // are disjoint it is not possible that an adjacent interval does not intersect, but a
+ // non-adjacent interval does intersect.
+ if (iter != m_allocations.end()) {
+ if (AllocationsIntersect(addr, size, iter->second.m_process_start, iter->second.m_size))
+ return true;
}
-
- while (iter != m_allocations.end() && iter->second.m_process_alloc < addr + size)
- {
- if (iter->second.m_process_start + iter->second.m_size > addr)
+
+ if (iter != m_allocations.begin()) {
+ --iter;
+ if (AllocationsIntersect(addr, size, iter->second.m_process_start, iter->second.m_size))
return true;
-
- ++iter;
}
-
+
return false;
}
+bool
+IRMemoryMap::AllocationsIntersect(lldb::addr_t addr1, size_t size1, lldb::addr_t addr2, size_t size2) {
+ // Given two half open intervals [A, B) and [X, Y), the only 6 permutations that satisfy
+ // A<B and X<Y are the following:
+ // A B X Y
+ // A X B Y (intersects)
+ // A X Y B (intersects)
+ // X A B Y (intersects)
+ // X A Y B (intersects)
+ // X Y A B
+ // The first is B <= X, and the last is Y <= A.
+ // So the condition is !(B <= X || Y <= A)), or (X < B && A < Y)
+ return (addr2 < (addr1 + size1)) && (addr1 < (addr2 + size2));
+}
+
lldb::ByteOrder
IRMemoryMap::GetByteOrder()
{
lldb::ProcessSP process_sp = m_process_wp.lock();
-
+
if (process_sp)
return process_sp->GetByteOrder();
-
+
lldb::TargetSP target_sp = m_target_wp.lock();
-
+
if (target_sp)
return target_sp->GetArchitecture().GetByteOrder();
-
+
return lldb::eByteOrderInvalid;
}
@@ -172,31 +165,31 @@ uint32_t
IRMemoryMap::GetAddressByteSize()
{
lldb::ProcessSP process_sp = m_process_wp.lock();
-
+
if (process_sp)
return process_sp->GetAddressByteSize();
-
+
lldb::TargetSP target_sp = m_target_wp.lock();
-
+
if (target_sp)
return target_sp->GetArchitecture().GetAddressByteSize();
-
+
return UINT32_MAX;
}
ExecutionContextScope *
-IRMemoryMap::GetBestExecutionContextScope()
+IRMemoryMap::GetBestExecutionContextScope() const
{
lldb::ProcessSP process_sp = m_process_wp.lock();
-
+
if (process_sp)
return process_sp.get();
-
+
lldb::TargetSP target_sp = m_target_wp.lock();
-
+
if (target_sp)
return target_sp.get();
-
+
return NULL;
}
@@ -234,8 +227,9 @@ IRMemoryMap::Allocation::Allocation (lldb::addr_t process_alloc,
lldb::addr_t
IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, Error &error)
{
+ lldb_private::Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
error.Clear();
-
+
lldb::ProcessSP process_sp;
lldb::addr_t allocation_address = LLDB_INVALID_ADDRESS;
lldb::addr_t aligned_address = LLDB_INVALID_ADDRESS;
@@ -247,7 +241,7 @@ IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, Alloc
allocation_size = alignment;
else
allocation_size = (size & alignment_mask) ? ((size + alignment) & (~alignment_mask)) : size;
-
+
switch (policy)
{
default:
@@ -265,6 +259,8 @@ IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, Alloc
break;
case eAllocationPolicyMirror:
process_sp = m_process_wp.lock();
+ if (log)
+ log->Printf ("IRMemoryMap::%s process_sp=0x%" PRIx64 ", process_sp->CanJIT()=%s, process_sp->IsAlive()=%s", __FUNCTION__, (lldb::addr_t) process_sp.get (), process_sp && process_sp->CanJIT () ? "true" : "false", process_sp && process_sp->IsAlive () ? "true" : "false");
if (process_sp && process_sp->CanJIT() && process_sp->IsAlive())
{
allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error);
@@ -273,6 +269,8 @@ IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, Alloc
}
else
{
+ if (log)
+ log->Printf ("IRMemoryMap::%s switching to eAllocationPolicyHostOnly due to failed condition (see previous expr log message)", __FUNCTION__);
policy = eAllocationPolicyHostOnly;
allocation_address = FindSpace(allocation_size);
if (allocation_address == LLDB_INVALID_ADDRESS)
@@ -308,8 +306,8 @@ IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, Alloc
}
break;
}
-
-
+
+
lldb::addr_t mask = alignment - 1;
aligned_address = (allocation_address + mask) & (~mask);
@@ -319,11 +317,11 @@ IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, Alloc
permissions,
alignment,
policy);
-
- if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+
+ if (log)
{
const char * policy_string;
-
+
switch (policy)
{
default:
@@ -339,7 +337,7 @@ IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, Alloc
policy_string = "eAllocationPolicyMirror";
break;
}
-
+
log->Printf("IRMemoryMap::Malloc (%" PRIu64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", %s) -> 0x%" PRIx64,
(uint64_t)allocation_size,
(uint64_t)alignment,
@@ -347,7 +345,7 @@ IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, Alloc
policy_string,
aligned_address);
}
-
+
return aligned_address;
}
@@ -355,16 +353,16 @@ void
IRMemoryMap::Leak (lldb::addr_t process_address, Error &error)
{
error.Clear();
-
+
AllocationMap::iterator iter = m_allocations.find(process_address);
-
+
if (iter == m_allocations.end())
{
error.SetErrorToGenericError();
error.SetErrorString("Couldn't leak: allocation doesn't exist");
return;
}
-
+
Allocation &allocation = iter->second;
allocation.m_leak = true;
@@ -374,18 +372,18 @@ void
IRMemoryMap::Free (lldb::addr_t process_address, Error &error)
{
error.Clear();
-
+
AllocationMap::iterator iter = m_allocations.find(process_address);
-
+
if (iter == m_allocations.end())
{
error.SetErrorToGenericError();
error.SetErrorString("Couldn't free: allocation doesn't exist");
return;
}
-
+
Allocation &allocation = iter->second;
-
+
switch (allocation.m_policy)
{
default:
@@ -397,7 +395,7 @@ IRMemoryMap::Free (lldb::addr_t process_address, Error &error)
if (process_sp->CanJIT() && process_sp->IsAlive())
process_sp->DeallocateMemory(allocation.m_process_alloc); // FindSpace allocated this for real
}
-
+
break;
}
case eAllocationPolicyMirror:
@@ -408,15 +406,15 @@ IRMemoryMap::Free (lldb::addr_t process_address, Error &error)
process_sp->DeallocateMemory(allocation.m_process_alloc);
}
}
-
+
if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
- {
+ {
log->Printf("IRMemoryMap::Free (0x%" PRIx64 ") freed [0x%" PRIx64 "..0x%" PRIx64 ")",
(uint64_t)process_address,
iter->second.m_process_start,
iter->second.m_process_start + iter->second.m_size);
}
-
+
m_allocations.erase(iter);
}
@@ -424,28 +422,28 @@ void
IRMemoryMap::WriteMemory (lldb::addr_t process_address, const uint8_t *bytes, size_t size, Error &error)
{
error.Clear();
-
+
AllocationMap::iterator iter = FindAllocation(process_address, size);
-
+
if (iter == m_allocations.end())
{
lldb::ProcessSP process_sp = m_process_wp.lock();
-
+
if (process_sp)
{
process_sp->WriteMemory(process_address, bytes, size, error);
return;
}
-
+
error.SetErrorToGenericError();
error.SetErrorString("Couldn't write: no allocation contains the target range and the process doesn't exist");
return;
}
-
+
Allocation &allocation = iter->second;
-
+
uint64_t offset = process_address - allocation.m_process_start;
-
+
lldb::ProcessSP process_sp;
switch (allocation.m_policy)
@@ -489,9 +487,9 @@ IRMemoryMap::WriteMemory (lldb::addr_t process_address, const uint8_t *bytes, si
}
break;
}
-
+
if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
- {
+ {
log->Printf("IRMemoryMap::WriteMemory (0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRId64 ") went to [0x%" PRIx64 "..0x%" PRIx64 ")",
(uint64_t)process_address,
(uint64_t)bytes,
@@ -505,10 +503,10 @@ void
IRMemoryMap::WriteScalarToMemory (lldb::addr_t process_address, Scalar &scalar, size_t size, Error &error)
{
error.Clear();
-
+
if (size == UINT32_MAX)
size = scalar.GetByteSize();
-
+
if (size > 0)
{
uint8_t buf[32];
@@ -535,9 +533,9 @@ void
IRMemoryMap::WritePointerToMemory (lldb::addr_t process_address, lldb::addr_t address, Error &error)
{
error.Clear();
-
+
Scalar scalar(address);
-
+
WriteScalarToMemory(process_address, scalar, GetAddressByteSize(), error);
}
@@ -545,39 +543,46 @@ void
IRMemoryMap::ReadMemory (uint8_t *bytes, lldb::addr_t process_address, size_t size, Error &error)
{
error.Clear();
-
+
AllocationMap::iterator iter = FindAllocation(process_address, size);
-
+
if (iter == m_allocations.end())
{
lldb::ProcessSP process_sp = m_process_wp.lock();
-
+
if (process_sp)
{
process_sp->ReadMemory(process_address, bytes, size, error);
return;
}
-
+
lldb::TargetSP target_sp = m_target_wp.lock();
-
+
if (target_sp)
{
Address absolute_address(process_address);
target_sp->ReadMemory(absolute_address, false, bytes, size, error);
return;
}
-
+
error.SetErrorToGenericError();
error.SetErrorString("Couldn't read: no allocation contains the target range, and neither the process nor the target exist");
return;
}
-
+
Allocation &allocation = iter->second;
-
+
uint64_t offset = process_address - allocation.m_process_start;
-
+
+ if (offset > allocation.m_size)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't read: data is not in the allocation");
+ return;
+ }
+
lldb::ProcessSP process_sp;
-
+
switch (allocation.m_policy)
{
default:
@@ -591,6 +596,13 @@ IRMemoryMap::ReadMemory (uint8_t *bytes, lldb::addr_t process_address, size_t si
error.SetErrorString("Couldn't read: data buffer is empty");
return;
}
+ if (allocation.m_data.GetByteSize() < offset + size)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't read: not enough underlying data");
+ return;
+ }
+
::memcpy (bytes, allocation.m_data.GetBytes() + offset, size);
break;
case eAllocationPolicyMirror:
@@ -622,7 +634,7 @@ IRMemoryMap::ReadMemory (uint8_t *bytes, lldb::addr_t process_address, size_t si
}
break;
}
-
+
if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
{
log->Printf("IRMemoryMap::ReadMemory (0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRId64 ") came from [0x%" PRIx64 "..0x%" PRIx64 ")",
@@ -638,19 +650,19 @@ void
IRMemoryMap::ReadScalarFromMemory (Scalar &scalar, lldb::addr_t process_address, size_t size, Error &error)
{
error.Clear();
-
+
if (size > 0)
{
DataBufferHeap buf(size, 0);
ReadMemory(buf.GetBytes(), process_address, size, error);
-
+
if (!error.Success())
return;
-
+
DataExtractor extractor(buf.GetBytes(), buf.GetByteSize(), GetByteOrder(), GetAddressByteSize());
-
+
lldb::offset_t offset = 0;
-
+
switch (size)
{
default:
@@ -675,15 +687,15 @@ void
IRMemoryMap::ReadPointerFromMemory (lldb::addr_t *address, lldb::addr_t process_address, Error &error)
{
error.Clear();
-
+
Scalar pointer_scalar;
ReadScalarFromMemory(pointer_scalar, process_address, GetAddressByteSize(), error);
-
+
if (!error.Success())
return;
-
+
*address = pointer_scalar.ULongLong();
-
+
return;
}
@@ -691,20 +703,20 @@ void
IRMemoryMap::GetMemoryData (DataExtractor &extractor, lldb::addr_t process_address, size_t size, Error &error)
{
error.Clear();
-
+
if (size > 0)
{
AllocationMap::iterator iter = FindAllocation(process_address, size);
-
+
if (iter == m_allocations.end())
{
error.SetErrorToGenericError();
error.SetErrorStringWithFormat("Couldn't find an allocation containing [0x%" PRIx64 "..0x%" PRIx64 ")", process_address, process_address + size);
return;
}
-
+
Allocation &allocation = iter->second;
-
+
switch (allocation.m_policy)
{
default:
@@ -754,5 +766,3 @@ IRMemoryMap::GetMemoryData (DataExtractor &extractor, lldb::addr_t process_addre
return;
}
}
-
-
diff --git a/source/Expression/Materializer.cpp b/source/Expression/Materializer.cpp
index 90687c0739d9..b11921635e5a 100644
--- a/source/Expression/Materializer.cpp
+++ b/source/Expression/Materializer.cpp
@@ -95,7 +95,7 @@ public:
}
if (log)
- log->Printf("Allocated %s (0x%" PRIx64 ") sucessfully", m_persistent_variable_sp->GetName().GetCString(), mem);
+ log->Printf("Allocated %s (0x%" PRIx64 ") successfully", m_persistent_variable_sp->GetName().GetCString(), mem);
// Put the location of the spare memory into the live data of the ValueObject.
@@ -443,10 +443,26 @@ public:
return;
}
+ Error valobj_error = valobj_sp->GetError();
+
+ if (valobj_error.Fail())
+ {
+ err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s", m_variable_sp->GetName().AsCString(), valobj_error.AsCString());
+ return;
+ }
+
if (m_is_reference)
{
DataExtractor valobj_extractor;
- valobj_sp->GetData(valobj_extractor);
+ Error extract_error;
+ valobj_sp->GetData(valobj_extractor, extract_error);
+
+ if (!extract_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't read contents of reference variable %s: %s", m_variable_sp->GetName().AsCString(), extract_error.AsCString());
+ return;
+ }
+
lldb::offset_t offset = 0;
lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
@@ -478,8 +494,14 @@ public:
else
{
DataExtractor data;
- valobj_sp->GetData(data);
-
+ Error extract_error;
+ valobj_sp->GetData(data, extract_error);
+ if (!extract_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't get the value of %s: %s", m_variable_sp->GetName().AsCString(), extract_error.AsCString());
+ return;
+ }
+
if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
{
err.SetErrorStringWithFormat("trying to create a temporary region for %s but one exists", m_variable_sp->GetName().AsCString());
@@ -513,6 +535,8 @@ public:
m_temporary_allocation = map.Malloc(data.GetByteSize(), byte_align, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, alloc_error);
m_temporary_allocation_size = data.GetByteSize();
+ m_original_data.reset(new DataBufferHeap(data.GetDataStart(), data.GetByteSize()));
+
if (!alloc_error.Success())
{
err.SetErrorStringWithFormat("couldn't allocate a temporary region for %s: %s", m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
@@ -585,14 +609,28 @@ public:
return;
}
- Error set_error;
+ bool actually_write = true;
- valobj_sp->SetData(data, set_error);
+ if (m_original_data)
+ {
+ if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
+ !memcmp(m_original_data->GetBytes(), data.GetDataStart(), data.GetByteSize()))
+ {
+ actually_write = false;
+ }
+ }
- if (!set_error.Success())
+ Error set_error;
+
+ if (actually_write)
{
- err.SetErrorStringWithFormat("couldn't write the new contents of %s back into the variable", m_variable_sp->GetName().AsCString());
- return;
+ valobj_sp->SetData(data, set_error);
+
+ if (!set_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the new contents of %s back into the variable", m_variable_sp->GetName().AsCString());
+ return;
+ }
}
Error free_error;
@@ -605,6 +643,7 @@ public:
return;
}
+ m_original_data.reset();
m_temporary_allocation = LLDB_INVALID_ADDRESS;
m_temporary_allocation_size = 0;
}
@@ -700,6 +739,7 @@ private:
bool m_is_reference;
lldb::addr_t m_temporary_allocation;
size_t m_temporary_allocation_size;
+ lldb::DataBufferSP m_original_data;
};
uint32_t
@@ -1312,43 +1352,44 @@ Materializer::DematerializerSP
Materializer::Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &error)
{
ExecutionContextScope *exe_scope = frame_sp.get();
-
+
if (!exe_scope)
exe_scope = map.GetBestExecutionContextScope();
-
+
DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
-
+
if (dematerializer_sp)
{
error.SetErrorToGenericError();
error.SetErrorString("Couldn't materialize: already materialized");
}
-
+
DematerializerSP ret(new Dematerializer(*this, frame_sp, map, process_address));
-
+
if (!exe_scope)
{
error.SetErrorToGenericError();
error.SetErrorString("Couldn't materialize: target doesn't exist");
}
-
+
for (EntityUP &entity_up : m_entities)
{
entity_up->Materialize(frame_sp, map, process_address, error);
-
+
if (!error.Success())
return DematerializerSP();
}
-
+
if (Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
{
- log->Printf("Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64 ") materialized:", frame_sp.get(), process_address);
+ log->Printf("Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64 ") materialized:",
+ static_cast<void*>(frame_sp.get()), process_address);
for (EntityUP &entity_up : m_entities)
entity_up->DumpToLog(map, process_address, log);
}
-
+
m_dematerializer_wp = ret;
-
+
return ret;
}
@@ -1360,15 +1401,15 @@ Materializer::Dematerializer::Dematerialize (Error &error, lldb::ClangExpression
lldb::ThreadSP thread_sp = m_thread_wp.lock();
if (thread_sp)
frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
-
+
ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope();
-
+
if (!IsValid())
{
error.SetErrorToGenericError();
error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
}
-
+
if (!exe_scope)
{
error.SetErrorToGenericError();
@@ -1378,11 +1419,12 @@ Materializer::Dematerializer::Dematerialize (Error &error, lldb::ClangExpression
{
if (Log *log =lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
{
- log->Printf("Materializer::Dematerialize (frame_sp = %p, process_address = 0x%" PRIx64 ") about to dematerialize:", frame_sp.get(), m_process_address);
+ log->Printf("Materializer::Dematerialize (frame_sp = %p, process_address = 0x%" PRIx64 ") about to dematerialize:",
+ static_cast<void*>(frame_sp.get()), m_process_address);
for (EntityUP &entity_up : m_materializer->m_entities)
entity_up->DumpToLog(*m_map, m_process_address, log);
}
-
+
for (EntityUP &entity_up : m_materializer->m_entities)
{
if (entity_up.get() == m_materializer->m_result_entity)
@@ -1393,12 +1435,12 @@ Materializer::Dematerializer::Dematerialize (Error &error, lldb::ClangExpression
{
entity_up->Dematerialize (frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error);
}
-
+
if (!error.Success())
break;
}
}
-
+
Wipe();
}
diff --git a/source/Host/common/Condition.cpp b/source/Host/common/Condition.cpp
index 7bc6b6554648..1c1afb4add7e 100644
--- a/source/Host/common/Condition.cpp
+++ b/source/Host/common/Condition.cpp
@@ -57,11 +57,6 @@ Condition::Signal ()
return ::pthread_cond_signal (&m_condition);
}
-/* convert struct timeval to ms(milliseconds) */
-static unsigned long int tv2ms(struct timeval a) {
- return ((a.tv_sec * 1000) + (a.tv_usec / 1000));
-}
-
//----------------------------------------------------------------------
// The Wait() function atomically blocks the current thread
// waiting on the owned condition variable, and unblocks the mutex
diff --git a/source/Host/common/DynamicLibrary.cpp b/source/Host/common/DynamicLibrary.cpp
deleted file mode 100644
index 315a675895ff..000000000000
--- a/source/Host/common/DynamicLibrary.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-//===-- DynamicLibrary.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/Core/Error.h"
-#include "lldb/Host/DynamicLibrary.h"
-
-using namespace lldb_private;
-
-DynamicLibrary::DynamicLibrary (const FileSpec& spec, uint32_t options) : m_filespec(spec)
-{
- Error err;
- m_handle = Host::DynamicLibraryOpen (spec,options,err);
- if (err.Fail())
- m_handle = NULL;
-}
-
-bool
-DynamicLibrary::IsValid ()
-{
- return m_handle != NULL;
-}
-
-DynamicLibrary::~DynamicLibrary ()
-{
- if (m_handle)
- Host::DynamicLibraryClose (m_handle);
-}
diff --git a/source/Host/common/Editline.cpp b/source/Host/common/Editline.cpp
index 679aadd54c4f..7af9f39a7863 100644
--- a/source/Host/common/Editline.cpp
+++ b/source/Host/common/Editline.cpp
@@ -20,30 +20,158 @@
using namespace lldb;
using namespace lldb_private;
+namespace lldb_private {
+ typedef std::weak_ptr<EditlineHistory> EditlineHistoryWP;
+
+
+ // EditlineHistory objects are sometimes shared between multiple
+ // Editline instances with the same program name. This class allows
+ // multiple editline instances to
+ //
+
+ class EditlineHistory
+ {
+ private:
+ // Use static GetHistory() function to get a EditlineHistorySP to one of these objects
+ EditlineHistory(const std::string &prefix, uint32_t size, bool unique_entries) :
+ m_history (NULL),
+ m_event (),
+ m_prefix (prefix),
+ m_path ()
+ {
+ m_history = ::history_init();
+ ::history (m_history, &m_event, H_SETSIZE, size);
+ if (unique_entries)
+ ::history (m_history, &m_event, H_SETUNIQUE, 1);
+ }
+
+ const char *
+ GetHistoryFilePath()
+ {
+ if (m_path.empty() && m_history && !m_prefix.empty())
+ {
+ char history_path[PATH_MAX];
+ ::snprintf (history_path, sizeof(history_path), "~/.%s-history", m_prefix.c_str());
+ m_path = std::move(FileSpec(history_path, true).GetPath());
+ }
+ if (m_path.empty())
+ return NULL;
+ return m_path.c_str();
+ }
+
+ public:
+
+ ~EditlineHistory()
+ {
+ Save ();
+
+ if (m_history)
+ {
+ ::history_end (m_history);
+ m_history = NULL;
+ }
+ }
+
+ static EditlineHistorySP
+ GetHistory (const std::string &prefix)
+ {
+ typedef std::map<std::string, EditlineHistoryWP> WeakHistoryMap;
+ static Mutex g_mutex(Mutex::eMutexTypeRecursive);
+ static WeakHistoryMap g_weak_map;
+ Mutex::Locker locker (g_mutex);
+ WeakHistoryMap::const_iterator pos = g_weak_map.find (prefix);
+ EditlineHistorySP history_sp;
+ if (pos != g_weak_map.end())
+ {
+ history_sp = pos->second.lock();
+ if (history_sp)
+ return history_sp;
+ g_weak_map.erase(pos);
+ }
+ history_sp.reset(new EditlineHistory(prefix, 800, true));
+ g_weak_map[prefix] = history_sp;
+ return history_sp;
+ }
+
+ bool IsValid() const
+ {
+ return m_history != NULL;
+ }
+
+ ::History *
+ GetHistoryPtr ()
+ {
+ return m_history;
+ }
+
+ void
+ Enter (const char *line_cstr)
+ {
+ if (m_history)
+ ::history (m_history, &m_event, H_ENTER, line_cstr);
+ }
+
+ bool
+ Load ()
+ {
+ if (m_history)
+ {
+ const char *path = GetHistoryFilePath();
+ if (path)
+ {
+ ::history (m_history, &m_event, H_LOAD, path);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool
+ Save ()
+ {
+ if (m_history)
+ {
+ const char *path = GetHistoryFilePath();
+ if (path)
+ {
+ ::history (m_history, &m_event, H_SAVE, path);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected:
+ ::History *m_history; // The history object
+ ::HistEvent m_event;// The history event needed to contain all history events
+ std::string m_prefix; // The prefix name (usually the editline program name) to use when loading/saving history
+ std::string m_path; // Path to the history file
+ };
+}
+
+
static const char k_prompt_escape_char = '\1';
Editline::Editline (const char *prog, // prog can't be NULL
const char *prompt, // can be NULL for no prompt
+ bool configure_for_multiline,
FILE *fin,
FILE *fout,
FILE *ferr) :
m_editline (NULL),
- m_history (NULL),
- m_history_event (),
- m_program (),
+ m_history_sp (),
m_prompt (),
m_lines_prompt (),
- m_getc_buffer (),
- m_getc_mutex (Mutex::eMutexTypeNormal),
- m_getc_cond (),
-// m_gets_mutex (Mutex::eMutexTypeNormal),
+ m_getting_char (false),
m_completion_callback (NULL),
m_completion_callback_baton (NULL),
m_line_complete_callback (NULL),
m_line_complete_callback_baton (NULL),
m_lines_command (Command::None),
+ m_line_offset (0),
m_lines_curr_line (0),
m_lines_max_line (0),
+ m_file (fileno(fin), false),
m_prompt_with_line_numbers (false),
m_getting_line (false),
m_got_eof (false),
@@ -51,14 +179,16 @@ Editline::Editline (const char *prog, // prog can't be NULL
{
if (prog && prog[0])
{
- m_program = prog;
m_editline = ::el_init(prog, fin, fout, ferr);
- m_history = ::history_init();
+
+ // Get a shared history instance
+ m_history_sp = EditlineHistory::GetHistory(prog);
}
else
{
m_editline = ::el_init("lldb-tmp", fin, fout, ferr);
}
+
if (prompt && prompt[0])
SetPrompt (prompt);
@@ -76,28 +206,44 @@ Editline::Editline (const char *prog, // prog can't be NULL
::el_set (m_editline, EL_PROMPT, GetPromptCallback);
#endif
::el_set (m_editline, EL_EDITOR, "emacs");
- if (m_history)
+ if (m_history_sp && m_history_sp->IsValid())
{
- ::el_set (m_editline, EL_HIST, history, m_history);
+ ::el_set (m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr());
}
::el_set (m_editline, EL_ADDFN, "lldb-complete", "Editline completion function", Editline::CallbackComplete);
+ // Keep old "lldb_complete" mapping for older clients that used this in their .editrc. editline also
+ // has a bad bug where if you have a bind command that tries to bind to a function name that doesn't
+ // exist, it will corrupt the heap and probably crash your process later.
+ ::el_set (m_editline, EL_ADDFN, "lldb_complete", "Editline completion function", Editline::CallbackComplete);
::el_set (m_editline, EL_ADDFN, "lldb-edit-prev-line", "Editline edit prev line", Editline::CallbackEditPrevLine);
::el_set (m_editline, EL_ADDFN, "lldb-edit-next-line", "Editline edit next line", Editline::CallbackEditNextLine);
::el_set (m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string
::el_set (m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does.
::el_set (m_editline, EL_BIND, "\033[3~", "ed-delete-next-char", NULL); // Fix the delete key.
- ::el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to be autocompelte
+ ::el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to be auto complete
+
+ if (configure_for_multiline)
+ {
+ // Use escape sequences for control characters due to bugs in editline
+ // where "-k up" and "-k down" don't always work.
+ ::el_set (m_editline, EL_BIND, "^[[A", "lldb-edit-prev-line", NULL); // Map up arrow
+ ::el_set (m_editline, EL_BIND, "^[[B", "lldb-edit-next-line", NULL); // Map down arrow
+ // Bindings for next/prev history
+ ::el_set (m_editline, EL_BIND, "^P", "ed-prev-history", NULL); // Map up arrow
+ ::el_set (m_editline, EL_BIND, "^N", "ed-next-history", NULL); // Map down arrow
+ }
+ else
+ {
+ // Use escape sequences for control characters due to bugs in editline
+ // where "-k up" and "-k down" don't always work.
+ ::el_set (m_editline, EL_BIND, "^[[A", "ed-prev-history", NULL); // Map up arrow
+ ::el_set (m_editline, EL_BIND, "^[[B", "ed-next-history", NULL); // Map down arrow
+ }
// Source $PWD/.editrc then $HOME/.editrc
::el_source (m_editline, NULL);
- if (m_history)
- {
- ::history (m_history, &m_history_event, H_SETSIZE, 800);
- ::history (m_history, &m_history_event, H_SETUNIQUE, 1);
- }
-
// Always read through our callback function so we don't read
// stuff we aren't supposed to. This also stops the extra echoing
// that can happen when you have more input than editline can handle
@@ -109,14 +255,12 @@ Editline::Editline (const char *prog, // prog can't be NULL
Editline::~Editline()
{
- SaveHistory();
-
- if (m_history)
- {
- ::history_end (m_history);
- m_history = NULL;
- }
-
+ // EditlineHistory objects are sometimes shared between multiple
+ // Editline instances with the same program name. So just release
+ // our shared pointer and if we are the last owner, it will save the
+ // history to the history save file automatically.
+ m_history_sp.reset();
+
// Disable edit mode to stop the terminal from flushing all input
// during the call to el_end() since we expect to have multiple editline
// instances in this program.
@@ -132,36 +276,19 @@ Editline::SetGetCharCallback (GetCharCallbackType callback)
::el_set (m_editline, EL_GETCFN, callback);
}
-FileSpec
-Editline::GetHistoryFile()
-{
- char history_path[PATH_MAX];
- ::snprintf (history_path, sizeof(history_path), "~/.%s-history", m_program.c_str());
- return FileSpec(history_path, true);
-}
-
bool
Editline::LoadHistory ()
{
- if (m_history)
- {
- FileSpec history_file(GetHistoryFile());
- if (history_file.Exists())
- ::history (m_history, &m_history_event, H_LOAD, history_file.GetPath().c_str());
- return true;
- }
+ if (m_history_sp)
+ return m_history_sp->Load();
return false;
}
bool
Editline::SaveHistory ()
{
- if (m_history)
- {
- std::string history_path = GetHistoryFile().GetPath();
- ::history (m_history, &m_history_event, H_SAVE, history_path.c_str());
- return true;
- }
+ if (m_history_sp)
+ return m_history_sp->Save();
return false;
}
@@ -180,13 +307,8 @@ Editline::PrivateGetLine(std::string &line)
if (m_editline != NULL)
{
int line_len = 0;
- const char *line_cstr = NULL;
// Call el_gets to prompt the user and read the user's input.
-// {
-// // Make sure we know when we are in el_gets() by using a mutex
-// Mutex::Locker locker (m_gets_mutex);
- line_cstr = ::el_gets (m_editline, &line_len);
-// }
+ const char *line_cstr = ::el_gets (m_editline, &line_len);
static int save_errno = (line_len < 0) ? errno : 0;
@@ -198,20 +320,18 @@ Editline::PrivateGetLine(std::string &line)
{
// Decrement the length so we don't have newline characters in "line" for when
// we assign the cstr into the std::string
- while (line_len > 0 &&
- (line_cstr[line_len - 1] == '\n' ||
- line_cstr[line_len - 1] == '\r'))
- --line_len;
+ llvm::StringRef line_ref (line_cstr);
+ line_ref = line_ref.rtrim("\n\r");
- if (line_len > 0)
+ if (!line_ref.empty() && !m_interrupted)
{
// We didn't strip the newlines, we just adjusted the length, and
// we want to add the history item with the newlines
- if (m_history)
- ::history (m_history, &m_history_event, H_ENTER, line_cstr);
+ if (m_history_sp)
+ m_history_sp->Enter(line_cstr);
// Copy the part of the c string that we want (removing the newline chars)
- line.assign(line_cstr, line_len);
+ line = std::move(line_ref.str());
}
}
}
@@ -224,15 +344,14 @@ Editline::PrivateGetLine(std::string &line)
Error
-Editline::GetLine(std::string &line)
+Editline::GetLine(std::string &line, bool &interrupted)
{
Error error;
+ interrupted = false;
line.clear();
// Set arrow key bindings for up and down arrows for single line
// mode where up and down arrows do prev/next history
- ::el_set (m_editline, EL_BIND, "^[[A", "ed-prev-history", NULL); // Map up arrow
- ::el_set (m_editline, EL_BIND, "^[[B", "ed-next-history", NULL); // Map down arrow
m_interrupted = false;
if (!m_got_eof)
@@ -252,6 +371,8 @@ Editline::GetLine(std::string &line)
m_getting_line = false;
}
+ interrupted = m_interrupted;
+
if (m_got_eof && line.empty())
{
// Only set the error if we didn't get an error back from PrivateGetLine()
@@ -278,9 +399,10 @@ Editline::Push (const char *bytes, size_t len)
Error
-Editline::GetLines(const std::string &end_line, StringList &lines)
+Editline::GetLines(const std::string &end_line, StringList &lines, bool &interrupted)
{
Error error;
+ interrupted = false;
if (m_getting_line)
{
error.SetErrorString("already getting a line");
@@ -294,10 +416,6 @@ Editline::GetLines(const std::string &end_line, StringList &lines)
// Set arrow key bindings for up and down arrows for multiple line
// mode where up and down arrows do edit prev/next line
- ::el_set (m_editline, EL_BIND, "^[[A", "lldb-edit-prev-line", NULL); // Map up arrow
- ::el_set (m_editline, EL_BIND, "^[[B", "lldb-edit-next-line", NULL); // Map down arrow
- ::el_set (m_editline, EL_BIND, "^b", "ed-prev-history", NULL);
- ::el_set (m_editline, EL_BIND, "^n", "ed-next-history", NULL);
m_interrupted = false;
LineStatus line_status = LineStatus::Success;
@@ -321,6 +439,11 @@ Editline::GetLines(const std::string &end_line, StringList &lines)
{
line_status = LineStatus::Error;
}
+ else if (m_interrupted)
+ {
+ interrupted = true;
+ line_status = LineStatus::Done;
+ }
else
{
switch (m_lines_command)
@@ -385,7 +508,7 @@ Editline::GetLines(const std::string &end_line, StringList &lines)
// If we have a callback, call it one more time to let the
// user know the lines are complete
- if (m_line_complete_callback)
+ if (m_line_complete_callback && !interrupted)
m_line_complete_callback (this,
lines,
UINT32_MAX,
@@ -599,70 +722,78 @@ Editline::GetPromptCallback (::EditLine *e)
return "";
}
-size_t
-Editline::SetInputBuffer (const char *c, size_t len)
-{
- if (c && len > 0)
- {
- Mutex::Locker locker(m_getc_mutex);
- SetGetCharCallback(GetCharInputBufferCallback);
- m_getc_buffer.append(c, len);
- m_getc_cond.Broadcast();
- }
- return len;
-}
-
-int
-Editline::GetChar (char *c)
-{
- Mutex::Locker locker(m_getc_mutex);
- if (m_getc_buffer.empty())
- m_getc_cond.Wait(m_getc_mutex);
- if (m_getc_buffer.empty())
- return 0;
- *c = m_getc_buffer[0];
- m_getc_buffer.erase(0,1);
- return 1;
-}
-
-int
-Editline::GetCharInputBufferCallback (EditLine *e, char *c)
-{
- Editline *editline = GetClientData (e);
- if (editline)
- return editline->GetChar(c);
- return 0;
-}
-
int
Editline::GetCharFromInputFileCallback (EditLine *e, char *c)
{
Editline *editline = GetClientData (e);
if (editline && editline->m_got_eof == false)
{
- char ch = ::fgetc(editline->GetInputFile());
- if (ch == '\x04')
- {
- // Only turn a CTRL+D into a EOF if we receive the
- // CTRL+D an empty line, otherwise it will forward
- // delete the character at the cursor
- const LineInfo *line_info = ::el_line(e);
- if (line_info != NULL &&
- line_info->buffer == line_info->cursor &&
- line_info->cursor == line_info->lastchar)
- {
- ch = EOF;
- }
- }
-
- if (ch == EOF)
+ FILE *f = editline->GetInputFile();
+ if (f == NULL)
{
editline->m_got_eof = true;
+ return 0;
}
- else
+
+
+ while (1)
{
- *c = ch;
- return 1;
+ lldb::ConnectionStatus status = eConnectionStatusSuccess;
+ char ch = 0;
+ // When we start to call el_gets() the editline library needs to
+ // output the prompt
+ editline->m_getting_char.SetValue(true, eBroadcastAlways);
+ const size_t n = editline->m_file.Read(&ch, 1, UINT32_MAX, status, NULL);
+ editline->m_getting_char.SetValue(false, eBroadcastAlways);
+ if (n)
+ {
+ if (ch == '\x04')
+ {
+ // Only turn a CTRL+D into a EOF if we receive the
+ // CTRL+D an empty line, otherwise it will forward
+ // delete the character at the cursor
+ const LineInfo *line_info = ::el_line(e);
+ if (line_info != NULL &&
+ line_info->buffer == line_info->cursor &&
+ line_info->cursor == line_info->lastchar)
+ {
+ editline->m_got_eof = true;
+ break;
+ }
+ }
+
+ if (status == eConnectionStatusEndOfFile)
+ {
+ editline->m_got_eof = true;
+ break;
+ }
+ else
+ {
+ *c = ch;
+ return 1;
+ }
+ }
+ else
+ {
+ switch (status)
+ {
+ case eConnectionStatusInterrupted:
+ editline->m_interrupted = true;
+ *c = '\n';
+ return 1;
+
+ case eConnectionStatusSuccess: // Success
+ break;
+
+ case eConnectionStatusError: // Check GetError() for details
+ case eConnectionStatusTimedOut: // Request timed out
+ case eConnectionStatusEndOfFile: // End-of-file encountered
+ case eConnectionStatusNoConnection: // No connection
+ case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
+ editline->m_got_eof = true;
+ break;
+ }
+ }
}
}
return 0;
@@ -671,12 +802,23 @@ Editline::GetCharFromInputFileCallback (EditLine *e, char *c)
void
Editline::Hide ()
{
- FILE *out_file = GetOutputFile();
- if (out_file)
+ if (m_getting_line)
{
- const LineInfo *line_info = ::el_line(m_editline);
- if (line_info)
- ::fprintf (out_file, "\033[%uD\033[K", (uint32_t)(strlen(GetPrompt()) + line_info->cursor - line_info->buffer));
+ // If we are getting a line, we might have started to call el_gets() and
+ // it might be printing the prompt. Here we make sure we are actually getting
+ // a character. This way we know the entire prompt has been printed.
+ TimeValue timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds(1);
+ if (m_getting_char.WaitForValueEqualTo(true, &timeout))
+ {
+ FILE *out_file = GetOutputFile();
+ if (out_file)
+ {
+ const LineInfo *line_info = ::el_line(m_editline);
+ if (line_info)
+ ::fprintf (out_file, "\033[%uD\033[K", (uint32_t)(strlen(GetPrompt()) + line_info->cursor - line_info->buffer));
+ }
+ }
}
}
@@ -684,13 +826,25 @@ Editline::Hide ()
void
Editline::Refresh()
{
- ::el_set (m_editline, EL_REFRESH);
+ if (m_getting_line)
+ {
+ // If we are getting a line, we might have started to call el_gets() and
+ // it might be printing the prompt. Here we make sure we are actually getting
+ // a character. This way we know the entire prompt has been printed.
+ TimeValue timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds(1);
+ if (m_getting_char.WaitForValueEqualTo(true, &timeout))
+ {
+ ::el_set (m_editline, EL_REFRESH);
+ }
+ }
}
-void
+bool
Editline::Interrupt ()
{
m_interrupted = true;
if (m_getting_line || m_lines_curr_line > 0)
- el_insertstr(m_editline, "\n"); // True to force the line to complete itself so we get exit from el_gets()
+ return m_file.InterruptRead();
+ return false; // Interrupt not handled as we weren't getting a line or lines
}
diff --git a/source/Host/common/File.cpp b/source/Host/common/File.cpp
index bb0ee39fbc7b..50513af2dc14 100644
--- a/source/Host/common/File.cpp
+++ b/source/Host/common/File.cpp
@@ -24,6 +24,7 @@
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
#include "lldb/Host/Config.h"
#include "lldb/Host/FileSpec.h"
@@ -77,11 +78,11 @@ int File::kInvalidDescriptor = -1;
FILE * File::kInvalidStream = NULL;
File::File(const char *path, uint32_t options, uint32_t permissions) :
+ IOObject(eFDTypeFile, false),
m_descriptor (kInvalidDescriptor),
m_stream (kInvalidStream),
m_options (),
m_own_stream (false),
- m_own_descriptor (false),
m_is_interactive (eLazyBoolCalculate),
m_is_real_terminal (eLazyBoolCalculate)
{
@@ -91,11 +92,11 @@ File::File(const char *path, uint32_t options, uint32_t permissions) :
File::File (const FileSpec& filespec,
uint32_t options,
uint32_t permissions) :
+ IOObject(eFDTypeFile, false),
m_descriptor (kInvalidDescriptor),
m_stream (kInvalidStream),
m_options (0),
m_own_stream (false),
- m_own_descriptor (false),
m_is_interactive (eLazyBoolCalculate),
m_is_real_terminal (eLazyBoolCalculate)
@@ -107,11 +108,11 @@ File::File (const FileSpec& filespec,
}
File::File (const File &rhs) :
+ IOObject(eFDTypeFile, false),
m_descriptor (kInvalidDescriptor),
m_stream (kInvalidStream),
m_options (0),
m_own_stream (false),
- m_own_descriptor (false),
m_is_interactive (eLazyBoolCalculate),
m_is_real_terminal (eLazyBoolCalculate)
{
@@ -148,13 +149,20 @@ File::GetDescriptor() const
return kInvalidDescriptor;
}
+IOObject::WaitableHandle
+File::GetWaitableHandle()
+{
+ return m_descriptor;
+}
+
+
void
File::SetDescriptor (int fd, bool transfer_ownership)
{
if (IsValid())
Close();
m_descriptor = fd;
- m_own_descriptor = transfer_ownership;
+ m_should_close_fd = transfer_ownership;
}
@@ -168,7 +176,7 @@ File::GetStream ()
const char *mode = GetStreamOpenModeFromOptions (m_options);
if (mode)
{
- if (!m_own_descriptor)
+ if (!m_should_close_fd)
{
// We must duplicate the file descriptor if we don't own it because
// when you call fdopen, the stream will own the fd
@@ -177,7 +185,7 @@ File::GetStream ()
#else
m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD);
#endif
- m_own_descriptor = true;
+ m_should_close_fd = true;
}
do
@@ -191,7 +199,7 @@ File::GetStream ()
if (m_stream)
{
m_own_stream = true;
- m_own_descriptor = false;
+ m_should_close_fd = false;
}
}
}
@@ -228,7 +236,7 @@ File::Duplicate (const File &rhs)
else
{
m_options = rhs.m_options;
- m_own_descriptor = true;
+ m_should_close_fd = true;
}
}
else
@@ -307,7 +315,7 @@ File::Open (const char *path, uint32_t options, uint32_t permissions)
error.SetErrorToErrno();
else
{
- m_own_descriptor = true;
+ m_should_close_fd = true;
m_options = options;
}
@@ -371,7 +379,7 @@ File::Close ()
error.SetErrorToErrno();
}
- if (DescriptorIsValid() && m_own_descriptor)
+ if (DescriptorIsValid() && m_should_close_fd)
{
if (::close (m_descriptor) != 0)
error.SetErrorToErrno();
@@ -380,7 +388,7 @@ File::Close ()
m_stream = kInvalidStream;
m_options = 0;
m_own_stream = false;
- m_own_descriptor = false;
+ m_should_close_fd = false;
m_is_interactive = eLazyBoolCalculate;
m_is_real_terminal = eLazyBoolCalculate;
return error;
@@ -669,6 +677,7 @@ File::Write (const void *buf, size_t &num_bytes)
num_bytes = 0;
error.SetErrorString("invalid file handle");
}
+
return error;
}
@@ -887,7 +896,13 @@ File::CalculateInteractiveAndTerminal ()
{
m_is_interactive = eLazyBoolNo;
m_is_real_terminal = eLazyBoolNo;
-#ifndef _MSC_VER
+#ifdef _WIN32
+ if (_isatty(fd))
+ {
+ m_is_interactive = eLazyBoolYes;
+ m_is_real_terminal = eLazyBoolYes;
+ }
+#else
if (isatty(fd))
{
m_is_interactive = eLazyBoolYes;
diff --git a/source/Host/common/FileCache.cpp b/source/Host/common/FileCache.cpp
new file mode 100644
index 000000000000..96b2a2ec02af
--- /dev/null
+++ b/source/Host/common/FileCache.cpp
@@ -0,0 +1,127 @@
+//===-- FileCache.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/Host/FileCache.h"
+
+#include "lldb/Host/File.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+FileCache *FileCache::m_instance = nullptr;
+
+FileCache &
+FileCache::GetInstance()
+{
+ if (m_instance == nullptr)
+ m_instance = new FileCache();
+
+ return *m_instance;
+}
+
+lldb::user_id_t
+FileCache::OpenFile(const FileSpec &file_spec, uint32_t flags, uint32_t mode, Error &error)
+{
+ std::string path(file_spec.GetPath());
+ if (path.empty())
+ {
+ error.SetErrorString("empty path");
+ return UINT64_MAX;
+ }
+ FileSP file_sp(new File());
+ error = file_sp->Open(path.c_str(), flags, mode);
+ if (file_sp->IsValid() == false)
+ return UINT64_MAX;
+ lldb::user_id_t fd = file_sp->GetDescriptor();
+ m_cache[fd] = file_sp;
+ return fd;
+}
+
+bool
+FileCache::CloseFile(lldb::user_id_t fd, Error &error)
+{
+ if (fd == UINT64_MAX)
+ {
+ error.SetErrorString("invalid file descriptor");
+ return false;
+ }
+ FDToFileMap::iterator pos = m_cache.find(fd);
+ if (pos == m_cache.end())
+ {
+ error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
+ return false;
+ }
+ FileSP file_sp = pos->second;
+ if (!file_sp)
+ {
+ error.SetErrorString("invalid host backing file");
+ return false;
+ }
+ error = file_sp->Close();
+ m_cache.erase(pos);
+ return error.Success();
+}
+
+uint64_t
+FileCache::WriteFile(lldb::user_id_t fd, uint64_t offset, const void *src, uint64_t src_len, Error &error)
+{
+ if (fd == UINT64_MAX)
+ {
+ error.SetErrorString("invalid file descriptor");
+ return UINT64_MAX;
+ }
+ FDToFileMap::iterator pos = m_cache.find(fd);
+ if (pos == m_cache.end())
+ {
+ error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
+ return false;
+ }
+ FileSP file_sp = pos->second;
+ if (!file_sp)
+ {
+ error.SetErrorString("invalid host backing file");
+ return UINT64_MAX;
+ }
+ if (static_cast<uint64_t>(file_sp->SeekFromStart(offset, &error)) != offset || error.Fail())
+ return UINT64_MAX;
+ size_t bytes_written = src_len;
+ error = file_sp->Write(src, bytes_written);
+ if (error.Fail())
+ return UINT64_MAX;
+ return bytes_written;
+}
+
+uint64_t
+FileCache::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, Error &error)
+{
+ if (fd == UINT64_MAX)
+ {
+ error.SetErrorString("invalid file descriptor");
+ return UINT64_MAX;
+ }
+ FDToFileMap::iterator pos = m_cache.find(fd);
+ if (pos == m_cache.end())
+ {
+ error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
+ return false;
+ }
+ FileSP file_sp = pos->second;
+ if (!file_sp)
+ {
+ error.SetErrorString("invalid host backing file");
+ return UINT64_MAX;
+ }
+ if (static_cast<uint64_t>(file_sp->SeekFromStart(offset, &error)) != offset || error.Fail())
+ return UINT64_MAX;
+ size_t bytes_read = dst_len;
+ error = file_sp->Read(dst, bytes_read);
+ if (error.Fail())
+ return UINT64_MAX;
+ return bytes_read;
+}
diff --git a/source/Host/common/FileSpec.cpp b/source/Host/common/FileSpec.cpp
index 48f1ac78d927..8c4014c074f5 100644
--- a/source/Host/common/FileSpec.cpp
+++ b/source/Host/common/FileSpec.cpp
@@ -27,21 +27,22 @@
#include <pwd.h>
#endif
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/File.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/Host.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataBufferMemoryMap.h"
#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/StreamString.h"
#include "lldb/Core/Stream.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Utility/CleanUp.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -54,104 +55,68 @@ GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr)
return false;
}
-#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
-
-static const char*
-GetCachedGlobTildeSlash()
-{
- static std::string g_tilde;
- if (g_tilde.empty())
- {
- struct passwd *user_entry;
- user_entry = getpwuid(geteuid());
- if (user_entry != NULL)
- g_tilde = user_entry->pw_dir;
-
- if (g_tilde.empty())
- return NULL;
- }
- return g_tilde.c_str();
-}
-
-#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
-
// Resolves the username part of a path of the form ~user/other/directories, and
// writes the result into dst_path.
-// Returns 0 if there WAS a ~ in the path but the username couldn't be resolved.
-// Otherwise returns the number of characters copied into dst_path. If the return
-// is >= dst_len, then the resolved path is too long...
-size_t
-FileSpec::ResolveUsername (const char *src_path, char *dst_path, size_t dst_len)
+void
+FileSpec::ResolveUsername (llvm::SmallVectorImpl<char> &path)
{
- if (src_path == NULL || src_path[0] == '\0')
- return 0;
-
-#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
-
- char user_home[PATH_MAX];
- const char *user_name;
-
-
- // If there's no ~, then just copy src_path straight to dst_path (they may be the same string...)
- if (src_path[0] != '~')
- {
- size_t len = strlen (src_path);
- if (len >= dst_len)
- {
- ::bcopy (src_path, dst_path, dst_len - 1);
- dst_path[dst_len] = '\0';
- }
- else
- ::bcopy (src_path, dst_path, len + 1);
-
- return len;
- }
-
- const char *first_slash = ::strchr (src_path, '/');
- char remainder[PATH_MAX];
+#if LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+ if (path.empty() || path[0] != '~')
+ return;
- if (first_slash == NULL)
+ llvm::StringRef path_str(path.data());
+ size_t slash_pos = path_str.find_first_of("/", 1);
+ if (slash_pos == 1)
{
- // The whole name is the username (minus the ~):
- user_name = src_path + 1;
- remainder[0] = '\0';
- }
- else
- {
- size_t user_name_len = first_slash - src_path - 1;
- ::memcpy (user_home, src_path + 1, user_name_len);
- user_home[user_name_len] = '\0';
- user_name = user_home;
+ // A path of the form ~/ resolves to the current user's home dir
+ llvm::SmallString<64> home_dir;
+ if (!llvm::sys::path::home_directory(home_dir))
+ return;
- ::strcpy (remainder, first_slash);
+ // Overwrite the ~ with the first character of the homedir, and insert
+ // the rest. This way we only trigger one move, whereas an insert
+ // followed by a delete (or vice versa) would trigger two.
+ path[0] = home_dir[0];
+ path.insert(path.begin() + 1, home_dir.begin() + 1, home_dir.end());
+ return;
}
- if (user_name == NULL)
- return 0;
- // User name of "" means the current user...
-
- struct passwd *user_entry;
- const char *home_dir = NULL;
-
- if (user_name[0] == '\0')
+ auto username_begin = path.begin()+1;
+ auto username_end = (slash_pos == llvm::StringRef::npos)
+ ? path.end()
+ : (path.begin() + slash_pos);
+ size_t replacement_length = std::distance(path.begin(), username_end);
+
+ llvm::SmallString<20> username(username_begin, username_end);
+ struct passwd *user_entry = ::getpwnam(username.c_str());
+ if (user_entry != nullptr)
{
- home_dir = GetCachedGlobTildeSlash();
+ // Copy over the first n characters of the path, where n is the smaller of the length
+ // of the home directory and the slash pos.
+ llvm::StringRef homedir(user_entry->pw_dir);
+ size_t initial_copy_length = std::min(homedir.size(), replacement_length);
+ auto src_begin = homedir.begin();
+ auto src_end = src_begin + initial_copy_length;
+ std::copy(src_begin, src_end, path.begin());
+ if (replacement_length > homedir.size())
+ {
+ // We copied the entire home directory, but the ~username portion of the path was
+ // longer, so there's characters that need to be removed.
+ path.erase(path.begin() + initial_copy_length, username_end);
+ }
+ else if (replacement_length < homedir.size())
+ {
+ // We copied all the way up to the slash in the destination, but there's still more
+ // characters that need to be inserted.
+ path.insert(username_end, src_end, homedir.end());
+ }
}
else
{
- user_entry = ::getpwnam (user_name);
- if (user_entry != NULL)
- home_dir = user_entry->pw_dir;
+ // Unable to resolve username (user doesn't exist?)
+ path.clear();
}
-
- if (home_dir == NULL)
- return 0;
- else
- return ::snprintf (dst_path, dst_len, "%s%s", home_dir, remainder);
-#else
- // Resolving home directories is not supported, just copy the path...
- return ::snprintf (dst_path, dst_len, "%s", src_path);
-#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+#endif
}
size_t
@@ -187,49 +152,24 @@ FileSpec::ResolvePartialUsername (const char *partial_name, StringList &matches)
#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
}
-
-
-size_t
-FileSpec::Resolve (const char *src_path, char *dst_path, size_t dst_len)
+void
+FileSpec::Resolve (llvm::SmallVectorImpl<char> &path)
{
- if (src_path == NULL || src_path[0] == '\0')
- return 0;
+ if (path.empty())
+ return;
- // Glob if needed for ~/, otherwise copy in case src_path is same as dst_path...
- char unglobbed_path[PATH_MAX];
#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
- if (src_path[0] == '~')
- {
- size_t return_count = ResolveUsername(src_path, unglobbed_path, sizeof(unglobbed_path));
-
- // If we couldn't find the user referred to, or the resultant path was too long,
- // then just copy over the src_path.
- if (return_count == 0 || return_count >= sizeof(unglobbed_path))
- ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", src_path);
- }
- else
+ if (path[0] == '~')
+ ResolveUsername(path);
#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
- {
- ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s", src_path);
- }
- // Now resolve the path if needed
- char resolved_path[PATH_MAX];
- if (::realpath (unglobbed_path, resolved_path))
- {
- // Success, copy the resolved path
- return ::snprintf(dst_path, dst_len, "%s", resolved_path);
- }
- else
- {
- // Failed, just copy the unglobbed path
- return ::snprintf(dst_path, dst_len, "%s", unglobbed_path);
- }
+ llvm::sys::fs::make_absolute(path);
}
-FileSpec::FileSpec() :
- m_directory(),
- m_filename()
+FileSpec::FileSpec()
+ : m_directory()
+ , m_filename()
+ , m_syntax(FileSystem::GetNativePathSyntax())
{
}
@@ -237,13 +177,13 @@ FileSpec::FileSpec() :
// Default constructor that can take an optional full path to a
// file on disk.
//------------------------------------------------------------------
-FileSpec::FileSpec(const char *pathname, bool resolve_path) :
+FileSpec::FileSpec(const char *pathname, bool resolve_path, PathSyntax syntax) :
m_directory(),
m_filename(),
m_is_resolved(false)
{
if (pathname && pathname[0])
- SetFile(pathname, resolve_path);
+ SetFile(pathname, resolve_path, syntax);
}
//------------------------------------------------------------------
@@ -252,7 +192,8 @@ FileSpec::FileSpec(const char *pathname, bool resolve_path) :
FileSpec::FileSpec(const FileSpec& rhs) :
m_directory (rhs.m_directory),
m_filename (rhs.m_filename),
- m_is_resolved (rhs.m_is_resolved)
+ m_is_resolved (rhs.m_is_resolved),
+ m_syntax (rhs.m_syntax)
{
}
@@ -268,7 +209,7 @@ FileSpec::FileSpec(const FileSpec* rhs) :
}
//------------------------------------------------------------------
-// Virtual destrcuctor in case anyone inherits from this class.
+// Virtual destructor in case anyone inherits from this class.
//------------------------------------------------------------------
FileSpec::~FileSpec()
{
@@ -285,83 +226,65 @@ FileSpec::operator= (const FileSpec& rhs)
m_directory = rhs.m_directory;
m_filename = rhs.m_filename;
m_is_resolved = rhs.m_is_resolved;
+ m_syntax = rhs.m_syntax;
}
return *this;
}
+void FileSpec::Normalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax)
+{
+ if (syntax == ePathSyntaxPosix ||
+ (syntax == ePathSyntaxHostNative && FileSystem::GetNativePathSyntax() == ePathSyntaxPosix))
+ return;
+
+ std::replace(path.begin(), path.end(), '\\', '/');
+}
+
+void FileSpec::DeNormalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax)
+{
+ if (syntax == ePathSyntaxPosix ||
+ (syntax == ePathSyntaxHostNative && FileSystem::GetNativePathSyntax() == ePathSyntaxPosix))
+ return;
+
+ std::replace(path.begin(), path.end(), '/', '\\');
+}
+
//------------------------------------------------------------------
// Update the contents of this object with a new path. The path will
// be split up into a directory and filename and stored as uniqued
// string values for quick comparison and efficient memory usage.
//------------------------------------------------------------------
void
-FileSpec::SetFile (const char *pathname, bool resolve)
+FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax)
{
m_filename.Clear();
m_directory.Clear();
m_is_resolved = false;
+ m_syntax = (syntax == ePathSyntaxHostNative) ? FileSystem::GetNativePathSyntax() : syntax;
+
if (pathname == NULL || pathname[0] == '\0')
return;
- char resolved_path[PATH_MAX];
- bool path_fit = true;
-
+ llvm::SmallString<64> normalized(pathname);
+ Normalize(normalized, syntax);
+
if (resolve)
{
- path_fit = (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1);
- m_is_resolved = path_fit;
+ FileSpec::Resolve (normalized);
+ m_is_resolved = true;
}
- else
- {
- // Copy the path because "basename" and "dirname" want to muck with the
- // path buffer
- if (::strlen (pathname) > sizeof(resolved_path) - 1)
- path_fit = false;
- else
- ::strcpy (resolved_path, pathname);
- }
-
- if (path_fit)
+ llvm::StringRef resolve_path_ref(normalized.c_str());
+ llvm::StringRef filename_ref = llvm::sys::path::filename(resolve_path_ref);
+ if (!filename_ref.empty())
{
- char *filename = ::basename (resolved_path);
- if (filename)
- {
- m_filename.SetCString (filename);
- // Truncate the basename off the end of the resolved path
-
- // Only attempt to get the dirname if it looks like we have a path
- if (strchr(resolved_path, '/')
-#ifdef _WIN32
- || strchr(resolved_path, '\\')
-#endif
- )
- {
- char *directory = ::dirname (resolved_path);
-
- // Make sure we didn't get our directory resolved to "." without having
- // specified
- if (directory)
- m_directory.SetCString(directory);
- else
- {
- char *last_resolved_path_slash = strrchr(resolved_path, '/');
-#ifdef _WIN32
- char* last_resolved_path_slash_windows = strrchr(resolved_path, '\\');
- if (last_resolved_path_slash_windows > last_resolved_path_slash)
- last_resolved_path_slash = last_resolved_path_slash_windows;
-#endif
- if (last_resolved_path_slash)
- {
- *last_resolved_path_slash = '\0';
- m_directory.SetCString(resolved_path);
- }
- }
- }
- }
- else
- m_directory.SetCString(resolved_path);
+ m_filename.SetString (filename_ref);
+ llvm::StringRef directory_ref = llvm::sys::path::parent_path(resolve_path_ref);
+ if (!directory_ref.empty())
+ m_directory.SetString(directory_ref);
}
+ else
+ m_directory.SetCString(normalized.c_str());
}
//----------------------------------------------------------------------
@@ -562,6 +485,15 @@ FileSpec::Exists () const
}
bool
+FileSpec::Readable () const
+{
+ const uint32_t permissions = GetPermissions();
+ if (permissions & eFilePermissionsEveryoneR)
+ return true;
+ return false;
+}
+
+bool
FileSpec::ResolveExecutableLocation ()
{
if (!m_directory)
@@ -572,8 +504,7 @@ FileSpec::ResolveExecutableLocation ()
const std::string file_str (file_cstr);
std::string path = llvm::sys::FindProgramByName (file_str);
llvm::StringRef dir_ref = llvm::sys::path::parent_path(path);
- //llvm::StringRef dir_ref = path.getDirname();
- if (! dir_ref.empty())
+ if (!dir_ref.empty())
{
// FindProgramByName returns "." if it can't find the file.
if (strcmp (".", dir_ref.data()) == 0)
@@ -607,7 +538,7 @@ FileSpec::ResolvePath ()
return true; // We have already resolved this path
char path_buf[PATH_MAX];
- if (!GetPath (path_buf, PATH_MAX))
+ if (!GetPath (path_buf, PATH_MAX, false))
return false;
// SetFile(...) will set m_is_resolved correctly if it can resolve the path
SetFile (path_buf, true);
@@ -623,6 +554,12 @@ FileSpec::GetByteSize() const
return 0;
}
+FileSpec::PathSyntax
+FileSpec::GetPathSyntax() const
+{
+ return m_syntax;
+}
+
FileSpec::FileType
FileSpec::GetFileType () const
{
@@ -652,7 +589,7 @@ FileSpec::GetPermissions () const
{
uint32_t file_permissions = 0;
if (*this)
- Host::GetFilePermissions(GetPath().c_str(), file_permissions);
+ FileSystem::GetFilePermissions(GetPath().c_str(), file_permissions);
return file_permissions;
}
@@ -708,45 +645,30 @@ FileSpec::GetFilename() const
// values.
//------------------------------------------------------------------
size_t
-FileSpec::GetPath(char *path, size_t path_max_len) const
+FileSpec::GetPath(char *path, size_t path_max_len, bool denormalize) const
{
- if (path_max_len)
- {
- const char *dirname = m_directory.GetCString();
- const char *filename = m_filename.GetCString();
- if (dirname)
- {
- if (filename)
- return ::snprintf (path, path_max_len, "%s/%s", dirname, filename);
- else
- return ::snprintf (path, path_max_len, "%s", dirname);
- }
- else if (filename)
- {
- return ::snprintf (path, path_max_len, "%s", filename);
- }
- }
- if (path)
- path[0] = '\0';
- return 0;
+ if (!path)
+ return 0;
+
+ std::string result = GetPath(denormalize);
+
+ size_t result_length = std::min(path_max_len-1, result.length());
+ ::strncpy(path, result.c_str(), result_length + 1);
+ return result_length;
}
std::string
-FileSpec::GetPath (void) const
+FileSpec::GetPath (bool denormalize) const
{
- static ConstString g_slash_only ("/");
- std::string path;
- const char *dirname = m_directory.GetCString();
- const char *filename = m_filename.GetCString();
- if (dirname)
- {
- path.append (dirname);
- if (filename && m_directory != g_slash_only)
- path.append ("/");
- }
- if (filename)
- path.append (filename);
- return path;
+ llvm::SmallString<64> result;
+ if (m_directory)
+ result.append(m_directory.GetCString());
+ if (m_filename)
+ llvm::sys::path::append(result, m_filename.GetCString());
+ if (denormalize && !result.empty())
+ DeNormalize(result, m_syntax);
+
+ return std::string(result.begin(), result.end());
}
ConstString
@@ -780,7 +702,7 @@ FileSpec::GetFileNameStrippingExtension () const
// Returns a shared pointer to a data buffer that contains all or
// part of the contents of a file. The data is memory mapped and
// will lazily page in data from the file as memory is accessed.
-// The data that is mappped will start "file_offset" bytes into the
+// The data that is mapped will start "file_offset" bytes into the
// file, and "file_size" bytes will be mapped. If "file_size" is
// greater than the number of bytes available in the file starting
// at "file_offset", the number of bytes will be appropriately
@@ -936,12 +858,11 @@ FileSpec::EnumerateDirectory
if (dir_path && dir_path[0])
{
#if _WIN32
- char szDir[MAX_PATH];
- strcpy_s(szDir, MAX_PATH, dir_path);
- strcat_s(szDir, MAX_PATH, "\\*");
+ std::string szDir(dir_path);
+ szDir += "\\*";
WIN32_FIND_DATA ffd;
- HANDLE hFind = FindFirstFile(szDir, &ffd);
+ HANDLE hFind = FindFirstFile(szDir.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp
index d43221c0e136..00c2fa37b383 100644
--- a/source/Host/common/Host.cpp
+++ b/source/Host/common/Host.cpp
@@ -12,11 +12,12 @@
// C includes
#include <errno.h>
#include <limits.h>
+#include <stdlib.h>
#include <sys/types.h>
#ifdef _WIN32
#include "lldb/Host/windows/windows.h"
#include <winsock2.h>
-#include <WS2tcpip.h>
+#include <ws2tcpip.h>
#else
#include <unistd.h>
#include <dlfcn.h>
@@ -35,10 +36,9 @@
#include <mach/mach_port.h>
#include <mach/mach_init.h>
#include <mach-o/dyld.h>
-#include <AvailabilityMacros.h>
#endif
-#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__)
+#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__) || defined(__NetBSD__)
#include <spawn.h>
#include <sys/wait.h>
#include <sys/syscall.h>
@@ -48,7 +48,11 @@
#include <pthread_np.h>
#endif
+// C++ includes
+#include <limits>
+
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Debugger.h"
@@ -60,13 +64,19 @@
#include "lldb/Host/Config.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Mutex.h"
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Target/FileAction.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Utility/CleanUp.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#if defined (__APPLE__)
@@ -85,6 +95,12 @@ extern "C"
using namespace lldb;
using namespace lldb_private;
+// Define maximum thread name length
+#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__NetBSD__)
+uint32_t const Host::MAX_THREAD_NAME_LENGTH = 16;
+#else
+uint32_t const Host::MAX_THREAD_NAME_LENGTH = std::numeric_limits<uint32_t>::max ();
+#endif
#if !defined (__APPLE__) && !defined (_WIN32)
struct MonitorInfo
@@ -116,7 +132,18 @@ Host::StartMonitoringChildProcess
info_ptr->monitor_signals = monitor_signals;
char thread_name[256];
- ::snprintf (thread_name, sizeof(thread_name), "<lldb.host.wait4(pid=%" PRIu64 ")>", pid);
+
+ if (Host::MAX_THREAD_NAME_LENGTH <= 16)
+ {
+ // On some platforms, the thread name is limited to 16 characters. We need to
+ // abbreviate there or the pid info would get truncated.
+ ::snprintf (thread_name, sizeof(thread_name), "wait4(%" PRIu64 ")", pid);
+ }
+ else
+ {
+ ::snprintf (thread_name, sizeof(thread_name), "<lldb.host.wait4(pid=%" PRIu64 ")>", pid);
+ }
+
thread = ThreadCreate (thread_name,
MonitorChildProcessThreadFunction,
info_ptr,
@@ -168,7 +195,7 @@ MonitorChildProcessThreadFunction (void *arg)
const bool monitor_signals = info->monitor_signals;
assert (info->pid <= UINT32_MAX);
- const ::pid_t pid = monitor_signals ? -1 * info->pid : info->pid;
+ const ::pid_t pid = monitor_signals ? -1 * getpgid(info->pid) : info->pid;
delete info;
@@ -302,181 +329,6 @@ Host::SystemLog (SystemLogType type, const char *format, ...)
va_end (args);
}
-const ArchSpec &
-Host::GetArchitecture (SystemDefaultArchitecture arch_kind)
-{
- static bool g_supports_32 = false;
- static bool g_supports_64 = false;
- static ArchSpec g_host_arch_32;
- static ArchSpec g_host_arch_64;
-
-#if defined (__APPLE__)
-
- // Apple is different in that it can support both 32 and 64 bit executables
- // in the same operating system running concurrently. Here we detect the
- // correct host architectures for both 32 and 64 bit including if 64 bit
- // executables are supported on the system.
-
- if (g_supports_32 == false && g_supports_64 == false)
- {
- // All apple systems support 32 bit execution.
- g_supports_32 = true;
- uint32_t cputype, cpusubtype;
- uint32_t is_64_bit_capable = false;
- size_t len = sizeof(cputype);
- ArchSpec host_arch;
- // These will tell us about the kernel architecture, which even on a 64
- // bit machine can be 32 bit...
- if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0)
- {
- len = sizeof (cpusubtype);
- if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) != 0)
- cpusubtype = CPU_TYPE_ANY;
-
- len = sizeof (is_64_bit_capable);
- if (::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0) == 0)
- {
- if (is_64_bit_capable)
- g_supports_64 = true;
- }
-
- if (is_64_bit_capable)
- {
-#if defined (__i386__) || defined (__x86_64__)
- if (cpusubtype == CPU_SUBTYPE_486)
- cpusubtype = CPU_SUBTYPE_I386_ALL;
-#endif
- if (cputype & CPU_ARCH_ABI64)
- {
- // We have a 64 bit kernel on a 64 bit system
- g_host_arch_32.SetArchitecture (eArchTypeMachO, ~(CPU_ARCH_MASK) & cputype, cpusubtype);
- g_host_arch_64.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
- }
- else
- {
- // We have a 32 bit kernel on a 64 bit system
- g_host_arch_32.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
- cputype |= CPU_ARCH_ABI64;
- g_host_arch_64.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
- }
- }
- else
- {
- g_host_arch_32.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
- g_host_arch_64.Clear();
- }
- }
- }
-
-#else // #if defined (__APPLE__)
-
- if (g_supports_32 == false && g_supports_64 == false)
- {
- llvm::Triple triple(llvm::sys::getDefaultTargetTriple());
-
- g_host_arch_32.Clear();
- g_host_arch_64.Clear();
-
- // If the OS is Linux, "unknown" in the vendor slot isn't what we want
- // for the default triple. It's probably an artifact of config.guess.
- if (triple.getOS() == llvm::Triple::Linux && triple.getVendor() == llvm::Triple::UnknownVendor)
- triple.setVendorName ("");
-
- const char* distribution_id = GetDistributionId ().AsCString();
-
- switch (triple.getArch())
- {
- default:
- g_host_arch_32.SetTriple(triple);
- g_host_arch_32.SetDistributionId (distribution_id);
- g_supports_32 = true;
- break;
-
- case llvm::Triple::x86_64:
- g_host_arch_64.SetTriple(triple);
- g_host_arch_64.SetDistributionId (distribution_id);
- g_supports_64 = true;
- g_host_arch_32.SetTriple(triple.get32BitArchVariant());
- g_host_arch_32.SetDistributionId (distribution_id);
- g_supports_32 = true;
- break;
-
- case llvm::Triple::sparcv9:
- case llvm::Triple::ppc64:
- g_host_arch_64.SetTriple(triple);
- g_host_arch_64.SetDistributionId (distribution_id);
- g_supports_64 = true;
- break;
- }
-
- g_supports_32 = g_host_arch_32.IsValid();
- g_supports_64 = g_host_arch_64.IsValid();
- }
-
-#endif // #else for #if defined (__APPLE__)
-
- if (arch_kind == eSystemDefaultArchitecture32)
- return g_host_arch_32;
- else if (arch_kind == eSystemDefaultArchitecture64)
- return g_host_arch_64;
-
- if (g_supports_64)
- return g_host_arch_64;
-
- return g_host_arch_32;
-}
-
-const ConstString &
-Host::GetVendorString()
-{
- static ConstString g_vendor;
- if (!g_vendor)
- {
- const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture);
- const llvm::StringRef &str_ref = host_arch.GetTriple().getVendorName();
- g_vendor.SetCStringWithLength(str_ref.data(), str_ref.size());
- }
- return g_vendor;
-}
-
-const ConstString &
-Host::GetOSString()
-{
- static ConstString g_os_string;
- if (!g_os_string)
- {
- const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture);
- const llvm::StringRef &str_ref = host_arch.GetTriple().getOSName();
- g_os_string.SetCStringWithLength(str_ref.data(), str_ref.size());
- }
- return g_os_string;
-}
-
-const ConstString &
-Host::GetTargetTriple()
-{
- static ConstString g_host_triple;
- if (!(g_host_triple))
- {
- const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture);
- g_host_triple.SetCString(host_arch.GetTriple().getTriple().c_str());
- }
- return g_host_triple;
-}
-
-// See linux/Host.cpp for Linux-based implementations of this.
-// Add your platform-specific implementation to the appropriate host file.
-#if !defined(__linux__)
-
-const ConstString &
- Host::GetDistributionId ()
-{
- static ConstString s_distribution_id;
- return s_distribution_id;
-}
-
-#endif // #if !defined(__linux__)
-
lldb::pid_t
Host::GetCurrentProcessID()
{
@@ -806,51 +658,6 @@ Host::SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid,
#endif
-FileSpec
-Host::GetProgramFileSpec ()
-{
- static FileSpec g_program_filespec;
- if (!g_program_filespec)
- {
-#if defined (__APPLE__)
- char program_fullpath[PATH_MAX];
- // If DST is NULL, then return the number of bytes needed.
- uint32_t len = sizeof(program_fullpath);
- int err = _NSGetExecutablePath (program_fullpath, &len);
- if (err == 0)
- g_program_filespec.SetFile (program_fullpath, false);
- else if (err == -1)
- {
- char *large_program_fullpath = (char *)::malloc (len + 1);
-
- err = _NSGetExecutablePath (large_program_fullpath, &len);
- if (err == 0)
- g_program_filespec.SetFile (large_program_fullpath, false);
-
- ::free (large_program_fullpath);
- }
-#elif defined (__linux__)
- char exe_path[PATH_MAX];
- ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
- if (len > 0) {
- exe_path[len] = 0;
- g_program_filespec.SetFile(exe_path, false);
- }
-#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
- int exe_path_mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, getpid() };
- size_t exe_path_size;
- if (sysctl(exe_path_mib, 4, NULL, &exe_path_size, NULL, 0) == 0)
- {
- char *exe_path = new char[exe_path_size];
- if (sysctl(exe_path_mib, 4, exe_path, &exe_path_size, NULL, 0) == 0)
- g_program_filespec.SetFile(exe_path, false);
- delete[] exe_path;
- }
-#endif
- }
- return g_program_filespec;
-}
-
#if !defined (__APPLE__) // see Host.mm
bool
@@ -869,130 +676,6 @@ Host::ResolveExecutableInBundle (FileSpec &file)
#ifndef _WIN32
-// Opaque info that tracks a dynamic library that was loaded
-struct DynamicLibraryInfo
-{
- DynamicLibraryInfo (const FileSpec &fs, int o, void *h) :
- file_spec (fs),
- open_options (o),
- handle (h)
- {
- }
-
- const FileSpec file_spec;
- uint32_t open_options;
- void * handle;
-};
-
-void *
-Host::DynamicLibraryOpen (const FileSpec &file_spec, uint32_t options, Error &error)
-{
- char path[PATH_MAX];
- if (file_spec.GetPath(path, sizeof(path)))
- {
- int mode = 0;
-
- if (options & eDynamicLibraryOpenOptionLazy)
- mode |= RTLD_LAZY;
- else
- mode |= RTLD_NOW;
-
-
- if (options & eDynamicLibraryOpenOptionLocal)
- mode |= RTLD_LOCAL;
- else
- mode |= RTLD_GLOBAL;
-
-#ifdef LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED
- if (options & eDynamicLibraryOpenOptionLimitGetSymbol)
- mode |= RTLD_FIRST;
-#endif
-
- void * opaque = ::dlopen (path, mode);
-
- if (opaque)
- {
- error.Clear();
- return new DynamicLibraryInfo (file_spec, options, opaque);
- }
- else
- {
- error.SetErrorString(::dlerror());
- }
- }
- else
- {
- error.SetErrorString("failed to extract path");
- }
- return NULL;
-}
-
-Error
-Host::DynamicLibraryClose (void *opaque)
-{
- Error error;
- if (opaque == NULL)
- {
- error.SetErrorString ("invalid dynamic library handle");
- }
- else
- {
- DynamicLibraryInfo *dylib_info = (DynamicLibraryInfo *) opaque;
- if (::dlclose (dylib_info->handle) != 0)
- {
- error.SetErrorString(::dlerror());
- }
-
- dylib_info->open_options = 0;
- dylib_info->handle = 0;
- delete dylib_info;
- }
- return error;
-}
-
-void *
-Host::DynamicLibraryGetSymbol (void *opaque, const char *symbol_name, Error &error)
-{
- if (opaque == NULL)
- {
- error.SetErrorString ("invalid dynamic library handle");
- }
- else
- {
- DynamicLibraryInfo *dylib_info = (DynamicLibraryInfo *) opaque;
-
- void *symbol_addr = ::dlsym (dylib_info->handle, symbol_name);
- if (symbol_addr)
- {
-#ifndef LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED
- // This host doesn't support limiting searches to this shared library
- // so we need to verify that the match came from this shared library
- // if it was requested in the Host::DynamicLibraryOpen() function.
- if (dylib_info->open_options & eDynamicLibraryOpenOptionLimitGetSymbol)
- {
- FileSpec match_dylib_spec (Host::GetModuleFileSpecForHostAddress (symbol_addr));
- if (match_dylib_spec != dylib_info->file_spec)
- {
- char dylib_path[PATH_MAX];
- if (dylib_info->file_spec.GetPath (dylib_path, sizeof(dylib_path)))
- error.SetErrorStringWithFormat ("symbol not found in \"%s\"", dylib_path);
- else
- error.SetErrorString ("symbol not found");
- return NULL;
- }
- }
-#endif
- error.Clear();
- return symbol_addr;
- }
- else
- {
- error.SetErrorString(::dlerror());
- }
- }
- return NULL;
-}
-
FileSpec
Host::GetModuleFileSpecForHostAddress (const void *host_addr)
{
@@ -1008,427 +691,6 @@ Host::GetModuleFileSpecForHostAddress (const void *host_addr)
#endif
-bool
-Host::GetLLDBPath (PathType path_type, FileSpec &file_spec)
-{
- // To get paths related to LLDB we get the path to the executable that
- // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB",
- // on linux this is assumed to be the "lldb" main executable. If LLDB on
- // linux is actually in a shared library (liblldb.so) then this function will
- // need to be modified to "do the right thing".
- Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST);
-
- switch (path_type)
- {
- case ePathTypeLLDBShlibDir:
- {
- static ConstString g_lldb_so_dir;
- if (!g_lldb_so_dir)
- {
- FileSpec lldb_file_spec (Host::GetModuleFileSpecForHostAddress ((void *)Host::GetLLDBPath));
- g_lldb_so_dir = lldb_file_spec.GetDirectory();
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_lldb_so_dir.GetCString());
- }
- file_spec.GetDirectory() = g_lldb_so_dir;
- return (bool)file_spec.GetDirectory();
- }
- break;
-
- case ePathTypeSupportExecutableDir:
- {
- static ConstString g_lldb_support_exe_dir;
- if (!g_lldb_support_exe_dir)
- {
- FileSpec lldb_file_spec;
- if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
- {
- char raw_path[PATH_MAX];
- char resolved_path[PATH_MAX];
- lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
-
-#if defined (__APPLE__)
- char *framework_pos = ::strstr (raw_path, "LLDB.framework");
- if (framework_pos)
- {
- framework_pos += strlen("LLDB.framework");
-#if defined (__arm__)
- // Shallow bundle
- *framework_pos = '\0';
-#else
- // Normal bundle
- ::strncpy (framework_pos, "/Resources", PATH_MAX - (framework_pos - raw_path));
-#endif
- }
-#endif
- FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
- g_lldb_support_exe_dir.SetCString(resolved_path);
- }
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", g_lldb_support_exe_dir.GetCString());
- }
- file_spec.GetDirectory() = g_lldb_support_exe_dir;
- return (bool)file_spec.GetDirectory();
- }
- break;
-
- case ePathTypeHeaderDir:
- {
- static ConstString g_lldb_headers_dir;
- if (!g_lldb_headers_dir)
- {
-#if defined (__APPLE__)
- FileSpec lldb_file_spec;
- if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
- {
- char raw_path[PATH_MAX];
- char resolved_path[PATH_MAX];
- lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
-
- char *framework_pos = ::strstr (raw_path, "LLDB.framework");
- if (framework_pos)
- {
- framework_pos += strlen("LLDB.framework");
- ::strncpy (framework_pos, "/Headers", PATH_MAX - (framework_pos - raw_path));
- }
- FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
- g_lldb_headers_dir.SetCString(resolved_path);
- }
-#else
- // TODO: Anyone know how we can determine this for linux? Other systems??
- g_lldb_headers_dir.SetCString ("/opt/local/include/lldb");
-#endif
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_lldb_headers_dir.GetCString());
- }
- file_spec.GetDirectory() = g_lldb_headers_dir;
- return (bool)file_spec.GetDirectory();
- }
- break;
-
-#ifdef LLDB_DISABLE_PYTHON
- case ePathTypePythonDir:
- return false;
-#else
- case ePathTypePythonDir:
- {
- static ConstString g_lldb_python_dir;
- if (!g_lldb_python_dir)
- {
- FileSpec lldb_file_spec;
- if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
- {
- char raw_path[PATH_MAX];
- char resolved_path[PATH_MAX];
- lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
-
-#if defined (__APPLE__)
- char *framework_pos = ::strstr (raw_path, "LLDB.framework");
- if (framework_pos)
- {
- framework_pos += strlen("LLDB.framework");
- ::strncpy (framework_pos, "/Resources/Python", PATH_MAX - (framework_pos - raw_path));
- }
- else
- {
-#endif
- llvm::SmallString<256> python_version_dir;
- llvm::raw_svector_ostream os(python_version_dir);
- os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION << "/site-packages";
- os.flush();
-
- // We may get our string truncated. Should we protect
- // this with an assert?
-
- ::strncat(raw_path, python_version_dir.c_str(),
- sizeof(raw_path) - strlen(raw_path) - 1);
-
-#if defined (__APPLE__)
- }
-#endif
- FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
- g_lldb_python_dir.SetCString(resolved_path);
- }
-
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypePythonDir) => '%s'", g_lldb_python_dir.GetCString());
-
- }
- file_spec.GetDirectory() = g_lldb_python_dir;
- return (bool)file_spec.GetDirectory();
- }
- break;
-#endif
-
- case ePathTypeLLDBSystemPlugins: // System plug-ins directory
- {
-#if defined (__APPLE__) || defined(__linux__)
- static ConstString g_lldb_system_plugin_dir;
- static bool g_lldb_system_plugin_dir_located = false;
- if (!g_lldb_system_plugin_dir_located)
- {
- g_lldb_system_plugin_dir_located = true;
-#if defined (__APPLE__)
- FileSpec lldb_file_spec;
- if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
- {
- char raw_path[PATH_MAX];
- char resolved_path[PATH_MAX];
- lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
-
- char *framework_pos = ::strstr (raw_path, "LLDB.framework");
- if (framework_pos)
- {
- framework_pos += strlen("LLDB.framework");
- ::strncpy (framework_pos, "/Resources/PlugIns", PATH_MAX - (framework_pos - raw_path));
- FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
- g_lldb_system_plugin_dir.SetCString(resolved_path);
- }
- return false;
- }
-#elif defined (__linux__)
- FileSpec lldb_file_spec("/usr/lib/lldb", true);
- if (lldb_file_spec.Exists())
- {
- g_lldb_system_plugin_dir.SetCString(lldb_file_spec.GetPath().c_str());
- }
-#endif // __APPLE__ || __linux__
-
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", g_lldb_system_plugin_dir.GetCString());
-
- }
-
- if (g_lldb_system_plugin_dir)
- {
- file_spec.GetDirectory() = g_lldb_system_plugin_dir;
- return true;
- }
-#else
- // TODO: where would system LLDB plug-ins be located on other systems?
- return false;
-#endif
- }
- break;
-
- case ePathTypeLLDBUserPlugins: // User plug-ins directory
- {
-#if defined (__APPLE__)
- static ConstString g_lldb_user_plugin_dir;
- if (!g_lldb_user_plugin_dir)
- {
- char user_plugin_path[PATH_MAX];
- if (FileSpec::Resolve ("~/Library/Application Support/LLDB/PlugIns",
- user_plugin_path,
- sizeof(user_plugin_path)))
- {
- g_lldb_user_plugin_dir.SetCString(user_plugin_path);
- }
- }
- file_spec.GetDirectory() = g_lldb_user_plugin_dir;
- return (bool)file_spec.GetDirectory();
-#elif defined (__linux__)
- static ConstString g_lldb_user_plugin_dir;
- if (!g_lldb_user_plugin_dir)
- {
- // XDG Base Directory Specification
- // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
- // If XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb.
- FileSpec lldb_file_spec;
- const char *xdg_data_home = getenv("XDG_DATA_HOME");
- if (xdg_data_home && xdg_data_home[0])
- {
- std::string user_plugin_dir (xdg_data_home);
- user_plugin_dir += "/lldb";
- lldb_file_spec.SetFile (user_plugin_dir.c_str(), true);
- }
- else
- {
- const char *home_dir = getenv("HOME");
- if (home_dir && home_dir[0])
- {
- std::string user_plugin_dir (home_dir);
- user_plugin_dir += "/.local/share/lldb";
- lldb_file_spec.SetFile (user_plugin_dir.c_str(), true);
- }
- }
-
- if (lldb_file_spec.Exists())
- g_lldb_user_plugin_dir.SetCString(lldb_file_spec.GetPath().c_str());
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", g_lldb_user_plugin_dir.GetCString());
- }
- file_spec.GetDirectory() = g_lldb_user_plugin_dir;
- return (bool)file_spec.GetDirectory();
-#endif
- // TODO: where would user LLDB plug-ins be located on other systems?
- return false;
- }
-
- case ePathTypeLLDBTempSystemDir:
- {
- static ConstString g_lldb_tmp_dir;
- if (!g_lldb_tmp_dir)
- {
- const char *tmpdir_cstr = getenv("TMPDIR");
- if (tmpdir_cstr == NULL)
- {
- tmpdir_cstr = getenv("TMP");
- if (tmpdir_cstr == NULL)
- tmpdir_cstr = getenv("TEMP");
- }
- if (tmpdir_cstr)
- {
- g_lldb_tmp_dir.SetCString(tmpdir_cstr);
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_lldb_tmp_dir.GetCString());
- }
- }
- file_spec.GetDirectory() = g_lldb_tmp_dir;
- return (bool)file_spec.GetDirectory();
- }
- }
-
- return false;
-}
-
-
-bool
-Host::GetHostname (std::string &s)
-{
- char hostname[PATH_MAX];
- hostname[sizeof(hostname) - 1] = '\0';
- if (::gethostname (hostname, sizeof(hostname) - 1) == 0)
- {
- struct hostent* h = ::gethostbyname (hostname);
- if (h)
- s.assign (h->h_name);
- else
- s.assign (hostname);
- return true;
- }
- return false;
-}
-
-#ifndef _WIN32
-
-const char *
-Host::GetUserName (uint32_t uid, std::string &user_name)
-{
- struct passwd user_info;
- struct passwd *user_info_ptr = &user_info;
- char user_buffer[PATH_MAX];
- size_t user_buffer_size = sizeof(user_buffer);
- if (::getpwuid_r (uid,
- &user_info,
- user_buffer,
- user_buffer_size,
- &user_info_ptr) == 0)
- {
- if (user_info_ptr)
- {
- user_name.assign (user_info_ptr->pw_name);
- return user_name.c_str();
- }
- }
- user_name.clear();
- return NULL;
-}
-
-const char *
-Host::GetGroupName (uint32_t gid, std::string &group_name)
-{
- char group_buffer[PATH_MAX];
- size_t group_buffer_size = sizeof(group_buffer);
- struct group group_info;
- struct group *group_info_ptr = &group_info;
- // Try the threadsafe version first
- if (::getgrgid_r (gid,
- &group_info,
- group_buffer,
- group_buffer_size,
- &group_info_ptr) == 0)
- {
- if (group_info_ptr)
- {
- group_name.assign (group_info_ptr->gr_name);
- return group_name.c_str();
- }
- }
- else
- {
- // The threadsafe version isn't currently working
- // for me on darwin, but the non-threadsafe version
- // is, so I am calling it below.
- group_info_ptr = ::getgrgid (gid);
- if (group_info_ptr)
- {
- group_name.assign (group_info_ptr->gr_name);
- return group_name.c_str();
- }
- }
- group_name.clear();
- return NULL;
-}
-
-uint32_t
-Host::GetUserID ()
-{
- return getuid();
-}
-
-uint32_t
-Host::GetGroupID ()
-{
- return getgid();
-}
-
-uint32_t
-Host::GetEffectiveUserID ()
-{
- return geteuid();
-}
-
-uint32_t
-Host::GetEffectiveGroupID ()
-{
- return getegid();
-}
-
-#endif
-
-#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) // see macosx/Host.mm
-bool
-Host::GetOSBuildString (std::string &s)
-{
- s.clear();
- return false;
-}
-
-bool
-Host::GetOSKernelDescription (std::string &s)
-{
- s.clear();
- return false;
-}
-#endif
-
-#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined(__linux__)
-uint32_t
-Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
-{
- process_infos.Clear();
- return process_infos.GetSize();
-}
-
-bool
-Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
-{
- process_info.Clear();
- return false;
-}
-#endif
-
#if !defined(__linux__)
bool
Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach)
@@ -1447,7 +709,7 @@ Host::GetDummyTarget (lldb_private::Debugger &debugger)
{
ArchSpec arch(Target::GetDefaultArchitecture());
if (!arch.IsValid())
- arch = Host::GetArchitecture ();
+ arch = HostInfo::GetArchitecture();
Error err = debugger.GetTargetList().CreateTarget(debugger,
NULL,
arch.GetTriple().getTriple().c_str(),
@@ -1545,9 +807,9 @@ Host::RunShellCommand (const char *command,
// output of the command into this file. We will later read this file
// if all goes well and fill the data into "command_output_ptr"
FileSpec tmpdir_file_spec;
- if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
{
- tmpdir_file_spec.GetFilename().SetCString("lldb-shell-output.XXXXXX");
+ tmpdir_file_spec.AppendPathComponent("lldb-shell-output.XXXXXX");
strncpy(output_file_path_buffer, tmpdir_file_spec.GetPath().c_str(), sizeof(output_file_path_buffer));
}
else
@@ -1601,7 +863,7 @@ Host::RunShellCommand (const char *command,
{
error.SetErrorString("timed out waiting for shell command to complete");
- // Kill the process since it didn't complete withint the timeout specified
+ // Kill the process since it didn't complete within the timeout specified
Kill (pid, SIGKILL);
// Wait for the monitor callback to get the message
timeout_time = TimeValue::Now();
@@ -1651,7 +913,7 @@ Host::RunShellCommand (const char *command,
// LaunchProcessPosixSpawn for Apple, Linux, FreeBSD and other GLIBC
// systems
-#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__)
+#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__)
// this method needs to be visible to macosx/Host.cpp and
// common/Host.cpp.
@@ -1682,7 +944,7 @@ Host::GetPosixspawnFlags (ProcessLaunchInfo &launch_info)
g_use_close_on_exec_flag = eLazyBoolNo;
uint32_t major, minor, update;
- if (Host::GetOSVersion(major, minor, update))
+ if (HostInfo::GetOSVersion(major, minor, update))
{
// Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or earlier
if (major > 10 || (major == 10 && minor > 7))
@@ -1757,8 +1019,8 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
cpu_type_t cpu = arch_spec.GetMachOCPUType();
cpu_type_t sub = arch_spec.GetMachOCPUSubType();
if (cpu != 0 &&
- cpu != UINT32_MAX &&
- cpu != LLDB_INVALID_CPUTYPE &&
+ cpu != static_cast<cpu_type_t>(UINT32_MAX) &&
+ cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) &&
!(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try to set the CPU type or we will fail
{
size_t ocount = 0;
@@ -1840,13 +1102,10 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
for (size_t i=0; i<num_file_actions; ++i)
{
- const ProcessLaunchInfo::FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i);
+ const FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i);
if (launch_file_action)
{
- if (!ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (&file_actions,
- launch_file_action,
- log,
- error))
+ if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log, error))
return error;
}
}
@@ -1862,12 +1121,10 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
if (error.Fail() || log)
{
error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )",
- pid,
- exe_path,
- &file_actions,
- &attr,
- argv,
- envp);
+ pid, exe_path, static_cast<void*>(&file_actions),
+ static_cast<void*>(&attr),
+ reinterpret_cast<const void*>(argv),
+ reinterpret_cast<const void*>(envp));
if (log)
{
for (int ii=0; argv[ii]; ++ii)
@@ -1889,11 +1146,9 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
if (error.Fail() || log)
{
error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )",
- pid,
- exe_path,
- &attr,
- argv,
- envp);
+ pid, exe_path, static_cast<void*>(&attr),
+ reinterpret_cast<const void*>(argv),
+ reinterpret_cast<const void*>(envp));
if (log)
{
for (int ii=0; argv[ii]; ++ii)
@@ -1920,12 +1175,79 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
return error;
}
+bool
+Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, Log *log, Error &error)
+{
+ if (info == NULL)
+ return false;
+
+ posix_spawn_file_actions_t *file_actions = reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions);
+
+ switch (info->GetAction())
+ {
+ case FileAction::eFileActionNone:
+ error.Clear();
+ break;
+
+ case FileAction::eFileActionClose:
+ if (info->GetFD() == -1)
+ error.SetErrorString("invalid fd for posix_spawn_file_actions_addclose(...)");
+ else
+ {
+ error.SetError(::posix_spawn_file_actions_addclose(file_actions, info->GetFD()), eErrorTypePOSIX);
+ if (log && (error.Fail() || log))
+ error.PutToLog(log, "posix_spawn_file_actions_addclose (action=%p, fd=%i)",
+ static_cast<void *>(file_actions), info->GetFD());
+ }
+ break;
+
+ case FileAction::eFileActionDuplicate:
+ if (info->GetFD() == -1)
+ error.SetErrorString("invalid fd for posix_spawn_file_actions_adddup2(...)");
+ else if (info->GetActionArgument() == -1)
+ error.SetErrorString("invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
+ else
+ {
+ error.SetError(
+ ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(), info->GetActionArgument()),
+ eErrorTypePOSIX);
+ if (log && (error.Fail() || log))
+ error.PutToLog(log, "posix_spawn_file_actions_adddup2 (action=%p, fd=%i, dup_fd=%i)",
+ static_cast<void *>(file_actions), info->GetFD(), info->GetActionArgument());
+ }
+ break;
+
+ case FileAction::eFileActionOpen:
+ if (info->GetFD() == -1)
+ error.SetErrorString("invalid fd in posix_spawn_file_actions_addopen(...)");
+ else
+ {
+ int oflag = info->GetActionArgument();
+
+ mode_t mode = 0;
+
+ if (oflag & O_CREAT)
+ mode = 0640;
+
+ error.SetError(
+ ::posix_spawn_file_actions_addopen(file_actions, info->GetFD(), info->GetPath(), oflag, mode),
+ eErrorTypePOSIX);
+ if (error.Fail() || log)
+ error.PutToLog(log,
+ "posix_spawn_file_actions_addopen (action=%p, fd=%i, path='%s', oflag=%i, mode=%i)",
+ static_cast<void *>(file_actions), info->GetFD(), info->GetPath(), oflag, mode);
+ }
+ break;
+ }
+ return error.Success();
+}
+
#endif // LaunchProcedssPosixSpawn: Apple, Linux, FreeBSD and other GLIBC systems
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__)
-// The functions below implement process launching via posix_spawn() for Linux
-// and FreeBSD.
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || defined(__NetBSD__)
+// The functions below implement process launching via posix_spawn() for Linux,
+// FreeBSD and NetBSD.
Error
Host::LaunchProcess (ProcessLaunchInfo &launch_info)
@@ -2005,58 +1327,10 @@ Host::LaunchProcess (ProcessLaunchInfo &launch_info)
return error;
}
-#endif // defined(__linux__) or defined(__FreeBSD__)
+#endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
#ifndef _WIN32
-size_t
-Host::GetPageSize()
-{
- return ::getpagesize();
-}
-
-uint32_t
-Host::GetNumberCPUS ()
-{
- static uint32_t g_num_cores = UINT32_MAX;
- if (g_num_cores == UINT32_MAX)
- {
-#if defined(__APPLE__) or defined (__linux__) or defined (__FreeBSD__) or defined (__FreeBSD_kernel__)
-
- g_num_cores = ::sysconf(_SC_NPROCESSORS_ONLN);
-
-#else
-
- // Assume POSIX support if a host specific case has not been supplied above
- g_num_cores = 0;
- int num_cores = 0;
- size_t num_cores_len = sizeof(num_cores);
-#ifdef HW_AVAILCPU
- int mib[] = { CTL_HW, HW_AVAILCPU };
-#else
- int mib[] = { CTL_HW, HW_NCPU };
-#endif
-
- /* get the number of CPUs from the system */
- if (sysctl(mib, sizeof(mib)/sizeof(int), &num_cores, &num_cores_len, NULL, 0) == 0 && (num_cores > 0))
- {
- g_num_cores = num_cores;
- }
- else
- {
- mib[1] = HW_NCPU;
- num_cores_len = sizeof(num_cores);
- if (sysctl(mib, sizeof(mib)/sizeof(int), &num_cores, &num_cores_len, NULL, 0) == 0 && (num_cores > 0))
- {
- if (num_cores > 0)
- g_num_cores = num_cores;
- }
- }
-#endif
- }
- return g_num_cores;
-}
-
void
Host::Kill(lldb::pid_t pid, int signo)
{
@@ -2090,319 +1364,13 @@ Host::LaunchApplication (const FileSpec &app_file_spec)
#endif
+#if !defined (__linux__) && !defined (__FreeBSD__) && !defined (__NetBSD__)
-#ifdef LLDB_DISABLE_POSIX
-
-Error
-Host::MakeDirectory (const char* path, uint32_t mode)
-{
- Error error;
- error.SetErrorStringWithFormat("%s in not implemented on this host", __PRETTY_FUNCTION__);
- return error;
-}
-
-Error
-Host::GetFilePermissions (const char* path, uint32_t &file_permissions)
-{
- Error error;
- error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
- return error;
-}
-
-Error
-Host::SetFilePermissions (const char* path, uint32_t file_permissions)
-{
- Error error;
- error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
- return error;
-}
-
-Error
-Host::Symlink (const char *src, const char *dst)
-{
- Error error;
- error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
- return error;
-}
-
-Error
-Host::Readlink (const char *path, char *buf, size_t buf_len)
-{
- Error error;
- error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
- return error;
-}
-
-Error
-Host::Unlink (const char *path)
-{
- Error error;
- error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
- return error;
-}
-
-#else
-
-Error
-Host::MakeDirectory (const char* path, uint32_t file_permissions)
-{
- Error error;
- if (path && path[0])
- {
- if (::mkdir(path, file_permissions) != 0)
- {
- error.SetErrorToErrno();
- switch (error.GetError())
- {
- case ENOENT:
- {
- // Parent directory doesn't exist, so lets make it if we can
- FileSpec spec(path, false);
- if (spec.GetDirectory() && spec.GetFilename())
- {
- // Make the parent directory and try again
- Error error2 = Host::MakeDirectory(spec.GetDirectory().GetCString(), file_permissions);
- if (error2.Success())
- {
- // Try and make the directory again now that the parent directory was made successfully
- if (::mkdir(path, file_permissions) == 0)
- error.Clear();
- else
- error.SetErrorToErrno();
- }
- }
- }
- break;
- case EEXIST:
- {
- FileSpec path_spec(path, false);
- if (path_spec.IsDirectory())
- error.Clear(); // It is a directory and it already exists
- }
- break;
- }
- }
- }
- else
- {
- error.SetErrorString("empty path");
- }
- return error;
-}
-
-Error
-Host::GetFilePermissions (const char* path, uint32_t &file_permissions)
-{
- Error error;
- struct stat file_stats;
- if (::stat (path, &file_stats) == 0)
- {
- // The bits in "st_mode" currently match the definitions
- // for the file mode bits in unix.
- file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
- }
- else
- {
- error.SetErrorToErrno();
- }
- return error;
-}
-
-Error
-Host::SetFilePermissions (const char* path, uint32_t file_permissions)
-{
- Error error;
- if (::chmod(path, file_permissions) != 0)
- error.SetErrorToErrno();
- return error;
-}
-
-Error
-Host::Symlink (const char *src, const char *dst)
-{
- Error error;
- if (::symlink(dst, src) == -1)
- error.SetErrorToErrno();
- return error;
-}
-
-Error
-Host::Unlink (const char *path)
-{
- Error error;
- if (::unlink(path) == -1)
- error.SetErrorToErrno();
- return error;
-}
-
-Error
-Host::Readlink (const char *path, char *buf, size_t buf_len)
-{
- Error error;
- ssize_t count = ::readlink(path, buf, buf_len);
- if (count < 0)
- error.SetErrorToErrno();
- else if (count < (buf_len-1))
- buf[count] = '\0'; // Success
- else
- error.SetErrorString("'buf' buffer is too small to contain link contents");
- return error;
-}
-
-
-#endif
-
-typedef std::map<lldb::user_id_t, lldb::FileSP> FDToFileMap;
-FDToFileMap& GetFDToFileMap()
-{
- static FDToFileMap g_fd2filemap;
- return g_fd2filemap;
-}
-
-lldb::user_id_t
-Host::OpenFile (const FileSpec& file_spec,
- uint32_t flags,
- uint32_t mode,
- Error &error)
+const lldb_private::UnixSignalsSP&
+Host::GetUnixSignals ()
{
- std::string path (file_spec.GetPath());
- if (path.empty())
- {
- error.SetErrorString("empty path");
- return UINT64_MAX;
- }
- FileSP file_sp(new File());
- error = file_sp->Open(path.c_str(),flags,mode);
- if (file_sp->IsValid() == false)
- return UINT64_MAX;
- lldb::user_id_t fd = file_sp->GetDescriptor();
- GetFDToFileMap()[fd] = file_sp;
- return fd;
+ static UnixSignalsSP s_unix_signals_sp (new UnixSignals ());
+ return s_unix_signals_sp;
}
-bool
-Host::CloseFile (lldb::user_id_t fd, Error &error)
-{
- if (fd == UINT64_MAX)
- {
- error.SetErrorString ("invalid file descriptor");
- return false;
- }
- FDToFileMap& file_map = GetFDToFileMap();
- FDToFileMap::iterator pos = file_map.find(fd);
- if (pos == file_map.end())
- {
- error.SetErrorStringWithFormat ("invalid host file descriptor %" PRIu64, fd);
- return false;
- }
- FileSP file_sp = pos->second;
- if (!file_sp)
- {
- error.SetErrorString ("invalid host backing file");
- return false;
- }
- error = file_sp->Close();
- file_map.erase(pos);
- return error.Success();
-}
-
-uint64_t
-Host::WriteFile (lldb::user_id_t fd, uint64_t offset, const void* src, uint64_t src_len, Error &error)
-{
- if (fd == UINT64_MAX)
- {
- error.SetErrorString ("invalid file descriptor");
- return UINT64_MAX;
- }
- FDToFileMap& file_map = GetFDToFileMap();
- FDToFileMap::iterator pos = file_map.find(fd);
- if (pos == file_map.end())
- {
- error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64 , fd);
- return false;
- }
- FileSP file_sp = pos->second;
- if (!file_sp)
- {
- error.SetErrorString ("invalid host backing file");
- return UINT64_MAX;
- }
- if (file_sp->SeekFromStart(offset, &error) != offset || error.Fail())
- return UINT64_MAX;
- size_t bytes_written = src_len;
- error = file_sp->Write(src, bytes_written);
- if (error.Fail())
- return UINT64_MAX;
- return bytes_written;
-}
-
-uint64_t
-Host::ReadFile (lldb::user_id_t fd, uint64_t offset, void* dst, uint64_t dst_len, Error &error)
-{
- if (fd == UINT64_MAX)
- {
- error.SetErrorString ("invalid file descriptor");
- return UINT64_MAX;
- }
- FDToFileMap& file_map = GetFDToFileMap();
- FDToFileMap::iterator pos = file_map.find(fd);
- if (pos == file_map.end())
- {
- error.SetErrorStringWithFormat ("invalid host file descriptor %" PRIu64, fd);
- return false;
- }
- FileSP file_sp = pos->second;
- if (!file_sp)
- {
- error.SetErrorString ("invalid host backing file");
- return UINT64_MAX;
- }
- if (file_sp->SeekFromStart(offset, &error) != offset || error.Fail())
- return UINT64_MAX;
- size_t bytes_read = dst_len;
- error = file_sp->Read(dst ,bytes_read);
- if (error.Fail())
- return UINT64_MAX;
- return bytes_read;
-}
-
-lldb::user_id_t
-Host::GetFileSize (const FileSpec& file_spec)
-{
- return file_spec.GetByteSize();
-}
-
-bool
-Host::GetFileExists (const FileSpec& file_spec)
-{
- return file_spec.Exists();
-}
-
-bool
-Host::CalculateMD5 (const FileSpec& file_spec,
- uint64_t &low,
- uint64_t &high)
-{
-#if defined (__APPLE__)
- StreamString md5_cmd_line;
- md5_cmd_line.Printf("md5 -q '%s'", file_spec.GetPath().c_str());
- std::string hash_string;
- Error err = Host::RunShellCommand(md5_cmd_line.GetData(), NULL, NULL, NULL, &hash_string, 60);
- if (err.Fail())
- return false;
- // a correctly formed MD5 is 16-bytes, that is 32 hex digits
- // if the output is any other length it is probably wrong
- if (hash_string.size() != 32)
- return false;
- std::string part1(hash_string,0,16);
- std::string part2(hash_string,16);
- const char* part1_cstr = part1.c_str();
- const char* part2_cstr = part2.c_str();
- high = ::strtoull(part1_cstr, NULL, 16);
- low = ::strtoull(part2_cstr, NULL, 16);
- return true;
-#else
- // your own MD5 implementation here
- return false;
#endif
-}
diff --git a/source/Host/common/HostInfoBase.cpp b/source/Host/common/HostInfoBase.cpp
new file mode 100644
index 000000000000..4eb43bfaf6ff
--- /dev/null
+++ b/source/Host/common/HostInfoBase.cpp
@@ -0,0 +1,318 @@
+//===-- HostInfoBase.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/Host/Config.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/HostInfoBase.h"
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Host.h"
+
+#include <thread>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+void
+CleanupProcessSpecificLLDBTempDir()
+{
+ // Get the process specific LLDB temporary directory and delete it.
+ FileSpec tmpdir_file_spec;
+ if (!HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
+ return;
+
+ // Remove the LLDB temporary directory if we have one. Set "recurse" to
+ // true to all files that were created for the LLDB process can be cleaned up.
+ FileSystem::DeleteDirectory(tmpdir_file_spec.GetDirectory().GetCString(), true);
+}
+
+struct HostInfoBaseFields
+{
+ uint32_t m_number_cpus;
+ std::string m_vendor_string;
+ std::string m_os_string;
+ std::string m_host_triple;
+
+ ArchSpec m_host_arch_32;
+ ArchSpec m_host_arch_64;
+
+ FileSpec m_lldb_so_dir;
+ FileSpec m_lldb_support_exe_dir;
+ FileSpec m_lldb_headers_dir;
+ FileSpec m_lldb_python_dir;
+ FileSpec m_lldb_system_plugin_dir;
+ FileSpec m_lldb_user_plugin_dir;
+ FileSpec m_lldb_tmp_dir;
+};
+
+HostInfoBaseFields *g_fields = nullptr;
+}
+
+#define COMPUTE_LLDB_PATH(compute_function, member_var) \
+ { \
+ static bool is_initialized = false; \
+ static bool success = false; \
+ if (!is_initialized) \
+ { \
+ is_initialized = true; \
+ success = HostInfo::compute_function(member_var); \
+ } \
+ if (success) \
+ result = &member_var; \
+ }
+
+void
+HostInfoBase::Initialize()
+{
+ g_fields = new HostInfoBaseFields();
+}
+
+uint32_t
+HostInfoBase::GetNumberCPUS()
+{
+ static bool is_initialized = false;
+ if (!is_initialized)
+ {
+ g_fields->m_number_cpus = std::thread::hardware_concurrency();
+ is_initialized = true;
+ }
+
+ return g_fields->m_number_cpus;
+}
+
+llvm::StringRef
+HostInfoBase::GetVendorString()
+{
+ static bool is_initialized = false;
+ if (!is_initialized)
+ {
+ const ArchSpec &host_arch = HostInfo::GetArchitecture();
+ const llvm::StringRef &str_ref = host_arch.GetTriple().getVendorName();
+ g_fields->m_vendor_string.assign(str_ref.begin(), str_ref.end());
+ is_initialized = true;
+ }
+ return g_fields->m_vendor_string;
+}
+
+llvm::StringRef
+HostInfoBase::GetOSString()
+{
+ static bool is_initialized = false;
+ if (!is_initialized)
+ {
+ const ArchSpec &host_arch = HostInfo::GetArchitecture();
+ const llvm::StringRef &str_ref = host_arch.GetTriple().getOSName();
+ g_fields->m_os_string.assign(str_ref.begin(), str_ref.end());
+ is_initialized = true;
+ }
+ return g_fields->m_os_string;
+}
+
+llvm::StringRef
+HostInfoBase::GetTargetTriple()
+{
+ static bool is_initialized = false;
+ if (!is_initialized)
+ {
+ const ArchSpec &host_arch = HostInfo::GetArchitecture();
+ g_fields->m_host_triple = host_arch.GetTriple().getTriple();
+ is_initialized = true;
+ }
+ return g_fields->m_host_triple;
+}
+
+const ArchSpec &
+HostInfoBase::GetArchitecture(ArchitectureKind arch_kind)
+{
+ static bool is_initialized = false;
+ if (!is_initialized)
+ {
+ HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, g_fields->m_host_arch_64);
+ is_initialized = true;
+ }
+
+ // If an explicit 32 or 64-bit architecture was requested, return that.
+ if (arch_kind == eArchKind32)
+ return g_fields->m_host_arch_32;
+ if (arch_kind == eArchKind64)
+ return g_fields->m_host_arch_64;
+
+ // Otherwise prefer the 64-bit architecture if it is valid.
+ return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 : g_fields->m_host_arch_32;
+}
+
+bool
+HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec)
+{
+ file_spec.Clear();
+
+#if defined(LLDB_DISABLE_PYTHON)
+ if (type == lldb::ePathTypePythonDir)
+ return false;
+#endif
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ FileSpec *result = nullptr;
+ switch (type)
+ {
+ case lldb::ePathTypeLLDBShlibDir:
+ COMPUTE_LLDB_PATH(ComputeSharedLibraryDirectory, g_fields->m_lldb_so_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str());
+ break;
+ case lldb::ePathTypeSupportExecutableDir:
+ COMPUTE_LLDB_PATH(ComputeSupportExeDirectory, g_fields->m_lldb_support_exe_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'",
+ g_fields->m_lldb_support_exe_dir.GetPath().c_str());
+ break;
+ case lldb::ePathTypeHeaderDir:
+ COMPUTE_LLDB_PATH(ComputeHeaderDirectory, g_fields->m_lldb_headers_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str());
+ break;
+ case lldb::ePathTypePythonDir:
+ COMPUTE_LLDB_PATH(ComputePythonDirectory, g_fields->m_lldb_python_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str());
+ break;
+ case lldb::ePathTypeLLDBSystemPlugins:
+ COMPUTE_LLDB_PATH(ComputeSystemPluginsDirectory, g_fields->m_lldb_system_plugin_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'",
+ g_fields->m_lldb_system_plugin_dir.GetPath().c_str());
+ break;
+ case lldb::ePathTypeLLDBUserPlugins:
+ COMPUTE_LLDB_PATH(ComputeUserPluginsDirectory, g_fields->m_lldb_user_plugin_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'",
+ g_fields->m_lldb_user_plugin_dir.GetPath().c_str());
+ break;
+ case lldb::ePathTypeLLDBTempSystemDir:
+ COMPUTE_LLDB_PATH(ComputeTempFileDirectory, g_fields->m_lldb_tmp_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_tmp_dir.GetPath().c_str());
+ break;
+ }
+
+ if (!result)
+ return false;
+ file_spec = *result;
+ return true;
+}
+
+bool
+HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec)
+{
+ // To get paths related to LLDB we get the path to the executable that
+ // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB",
+ // on linux this is assumed to be the "lldb" main executable. If LLDB on
+ // linux is actually in a shared library (liblldb.so) then this function will
+ // need to be modified to "do the right thing".
+
+ FileSpec lldb_file_spec(
+ Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>(reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath))));
+
+ // Remove the filename so that this FileSpec only represents the directory.
+ file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
+
+ return (bool)file_spec.GetDirectory();
+}
+
+bool
+HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec)
+{
+ return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec);
+}
+
+bool
+HostInfoBase::ComputeTempFileDirectory(FileSpec &file_spec)
+{
+ const char *tmpdir_cstr = getenv("TMPDIR");
+ if (tmpdir_cstr == NULL)
+ {
+ tmpdir_cstr = getenv("TMP");
+ if (tmpdir_cstr == NULL)
+ tmpdir_cstr = getenv("TEMP");
+ }
+ if (!tmpdir_cstr)
+ return false;
+
+ StreamString pid_tmpdir;
+ pid_tmpdir.Printf("%s/lldb", tmpdir_cstr);
+ if (!FileSystem::MakeDirectory(pid_tmpdir.GetString().c_str(), eFilePermissionsDirectoryDefault).Success())
+ return false;
+
+ pid_tmpdir.Printf("/%" PRIu64, Host::GetCurrentProcessID());
+ if (!FileSystem::MakeDirectory(pid_tmpdir.GetString().c_str(), eFilePermissionsDirectoryDefault).Success())
+ return false;
+
+ // Make an atexit handler to clean up the process specify LLDB temp dir
+ // and all of its contents.
+ ::atexit(CleanupProcessSpecificLLDBTempDir);
+ file_spec.GetDirectory().SetCStringWithLength(pid_tmpdir.GetString().c_str(), pid_tmpdir.GetString().size());
+ return true;
+}
+
+bool
+HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec)
+{
+ // TODO(zturner): Figure out how to compute the header directory for all platforms.
+ return false;
+}
+
+bool
+HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec)
+{
+ // TODO(zturner): Figure out how to compute the system plugins directory for all platforms.
+ return false;
+}
+
+bool
+HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec)
+{
+ // TODO(zturner): Figure out how to compute the user plugins directory for all platforms.
+ return false;
+}
+
+void
+HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64)
+{
+ llvm::Triple triple(llvm::sys::getDefaultTargetTriple());
+
+ arch_32.Clear();
+ arch_64.Clear();
+
+ switch (triple.getArch())
+ {
+ default:
+ arch_32.SetTriple(triple);
+ break;
+
+ case llvm::Triple::x86_64:
+ arch_64.SetTriple(triple);
+ arch_32.SetTriple(triple.get32BitArchVariant());
+ break;
+
+ case llvm::Triple::aarch64:
+ case llvm::Triple::mips64:
+ case llvm::Triple::sparcv9:
+ case llvm::Triple::ppc64:
+ arch_64.SetTriple(triple);
+ break;
+ }
+}
diff --git a/source/Host/common/IOObject.cpp b/source/Host/common/IOObject.cpp
new file mode 100644
index 000000000000..6f7de442be1d
--- /dev/null
+++ b/source/Host/common/IOObject.cpp
@@ -0,0 +1,14 @@
+//===-- IOObject.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/Host/IOObject.h"
+
+using namespace lldb_private;
+
+const IOObject::WaitableHandle IOObject::kInvalidHandleValue = -1;
diff --git a/source/Host/common/Mutex.cpp b/source/Host/common/Mutex.cpp
index 4e0135535628..c26467fa0d79 100644
--- a/source/Host/common/Mutex.cpp
+++ b/source/Host/common/Mutex.cpp
@@ -242,9 +242,9 @@ Mutex::Mutex (Mutex::Type type) :
//----------------------------------------------------------------------
Mutex::~Mutex()
{
+#if ENABLE_MUTEX_ERROR_CHECKING
int err = ::pthread_mutex_destroy (&m_mutex);
assert(err == 0);
-#if ENABLE_MUTEX_ERROR_CHECKING
if (err == 0)
error_check_mutex (&m_mutex, eMutexActionDestroyed);
else
@@ -253,6 +253,8 @@ Mutex::~Mutex()
assert(err == 0);
}
memset (&m_mutex, '\xba', sizeof(m_mutex));
+#else
+ ::pthread_mutex_destroy (&m_mutex);
#endif
}
diff --git a/source/Host/common/NativeBreakpoint.cpp b/source/Host/common/NativeBreakpoint.cpp
new file mode 100644
index 000000000000..284d7d11d6ce
--- /dev/null
+++ b/source/Host/common/NativeBreakpoint.cpp
@@ -0,0 +1,116 @@
+//===-- NativeBreakpoint.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeBreakpoint.h"
+
+#include "lldb/lldb-defines.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb_private;
+
+NativeBreakpoint::NativeBreakpoint (lldb::addr_t addr) :
+ m_addr (addr),
+ m_ref_count (1),
+ m_enabled (true)
+{
+ assert (addr != LLDB_INVALID_ADDRESS && "breakpoint set for invalid address");
+}
+
+NativeBreakpoint::~NativeBreakpoint ()
+{
+}
+
+void
+NativeBreakpoint::AddRef ()
+{
+ ++m_ref_count;
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " bumped up, new ref count %" PRIu32, __FUNCTION__, m_addr, m_ref_count);
+}
+
+int32_t
+NativeBreakpoint::DecRef ()
+{
+ --m_ref_count;
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " ref count decremented, new ref count %" PRIu32, __FUNCTION__, m_addr, m_ref_count);
+
+ return m_ref_count;
+}
+
+Error
+NativeBreakpoint::Enable ()
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (m_enabled)
+ {
+ // We're already enabled. Just log and exit.
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " already enabled, ignoring.", __FUNCTION__, m_addr);
+ return Error ();
+ }
+
+ // Log and enable.
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enabling...", __FUNCTION__, m_addr);
+
+ Error error = DoEnable ();
+ if (error.Success ())
+ {
+ m_enabled = true;
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enable SUCCESS.", __FUNCTION__, m_addr);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enable FAIL: %s", __FUNCTION__, m_addr, error.AsCString ());
+ }
+
+ return error;
+}
+
+Error
+NativeBreakpoint::Disable ()
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (!m_enabled)
+ {
+ // We're already disabled. Just log and exit.
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " already disabled, ignoring.", __FUNCTION__, m_addr);
+ return Error ();
+ }
+
+ // Log and disable.
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disabling...", __FUNCTION__, m_addr);
+
+ Error error = DoDisable ();
+ if (error.Success ())
+ {
+ m_enabled = false;
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disable SUCCESS.", __FUNCTION__, m_addr);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disable FAIL: %s", __FUNCTION__, m_addr, error.AsCString ());
+ }
+
+ return error;
+}
diff --git a/source/Host/common/NativeBreakpoint.h b/source/Host/common/NativeBreakpoint.h
new file mode 100644
index 000000000000..367003b94e35
--- /dev/null
+++ b/source/Host/common/NativeBreakpoint.h
@@ -0,0 +1,66 @@
+//===-- NativeBreakpoint.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_NativeBreakpoint_h_
+#define liblldb_NativeBreakpoint_h_
+
+#include "lldb/lldb-types.h"
+
+namespace lldb_private
+{
+ class NativeBreakpointList;
+
+ class NativeBreakpoint
+ {
+ friend class NativeBreakpointList;
+
+ public:
+ // The assumption is that derived breakpoints are enabled when created.
+ NativeBreakpoint (lldb::addr_t addr);
+
+ virtual
+ ~NativeBreakpoint ();
+
+ Error
+ Enable ();
+
+ Error
+ Disable ();
+
+ lldb::addr_t
+ GetAddress () const { return m_addr; }
+
+ bool
+ IsEnabled () const { return m_enabled; }
+
+ virtual bool
+ IsSoftwareBreakpoint () const = 0;
+
+ protected:
+ const lldb::addr_t m_addr;
+ int32_t m_ref_count;
+
+ virtual Error
+ DoEnable () = 0;
+
+ virtual Error
+ DoDisable () = 0;
+
+ private:
+ bool m_enabled;
+
+ // -----------------------------------------------------------
+ // interface for NativeBreakpointList
+ // -----------------------------------------------------------
+ void AddRef ();
+ int32_t DecRef ();
+ };
+}
+
+#endif // ifndef liblldb_NativeBreakpoint_h_
diff --git a/source/Host/common/NativeBreakpointList.cpp b/source/Host/common/NativeBreakpointList.cpp
new file mode 100644
index 000000000000..ecd0624bde09
--- /dev/null
+++ b/source/Host/common/NativeBreakpointList.cpp
@@ -0,0 +1,199 @@
+//===-- NativeBreakpointList.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeBreakpointList.h"
+
+#include "lldb/Core/Log.h"
+
+#include "NativeBreakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+NativeBreakpointList::NativeBreakpointList () :
+ m_mutex (Mutex::eMutexTypeRecursive)
+{
+}
+
+Error
+NativeBreakpointList::AddRef (lldb::addr_t addr, size_t size_hint, bool hardware, CreateBreakpointFunc create_func)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false");
+
+ Mutex::Locker locker (m_mutex);
+
+ // Check if the breakpoint is already set.
+ auto iter = m_breakpoints.find (addr);
+ if (iter != m_breakpoints.end ())
+ {
+ // Yes - bump up ref count.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- already enabled, upping ref count", __FUNCTION__, addr);
+
+ iter->second->AddRef ();
+ return Error ();
+ }
+
+ // Create a new breakpoint using the given create func.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false");
+
+ NativeBreakpointSP breakpoint_sp;
+ Error error = create_func (addr, size_hint, hardware, breakpoint_sp);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s -- FAILED: %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false", error.AsCString ());
+ return error;
+ }
+
+ // Remember the breakpoint.
+ assert (breakpoint_sp && "NativeBreakpoint create function succeeded but returned NULL breakpoint");
+ m_breakpoints.insert (BreakpointMap::value_type (addr, breakpoint_sp));
+
+ return error;
+}
+
+Error
+NativeBreakpointList::DecRef (lldb::addr_t addr)
+{
+ Error error;
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ Mutex::Locker locker (m_mutex);
+
+ // Check if the breakpoint is already set.
+ auto iter = m_breakpoints.find (addr);
+ if (iter == m_breakpoints.end ())
+ {
+ // Not found!
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr);
+ error.SetErrorString ("breakpoint not found");
+ return error;
+ }
+
+ // Decrement ref count.
+ const int32_t new_ref_count = iter->second->DecRef ();
+ assert (new_ref_count >= 0 && "NativeBreakpoint ref count went negative");
+
+ if (new_ref_count > 0)
+ {
+ // Still references to this breakpoint. Leave it alone.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- new breakpoint ref count %" PRIu32, __FUNCTION__, addr, new_ref_count);
+ return error;
+ }
+
+ // Breakpoint has no more references. Disable it if it's not
+ // already disabled.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removing due to no remaining references", __FUNCTION__, addr);
+
+ // If it's enabled, we need to disable it.
+ if (iter->second->IsEnabled ())
+ {
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- currently enabled, now disabling", __FUNCTION__, addr);
+ error = iter->second->Disable ();
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removal FAILED: %s", __FUNCTION__, addr, error.AsCString ());
+ // Continue since we still want to take it out of the breakpoint list.
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- already disabled, nothing to do", __FUNCTION__, addr);
+ }
+
+ // Take the breakpoint out of the list.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removed from breakpoint map", __FUNCTION__, addr);
+
+ m_breakpoints.erase (iter);
+ return error;
+}
+
+Error
+NativeBreakpointList::EnableBreakpoint (lldb::addr_t addr)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ Mutex::Locker locker (m_mutex);
+
+ // Ensure we have said breakpoint.
+ auto iter = m_breakpoints.find (addr);
+ if (iter == m_breakpoints.end ())
+ {
+ // Not found!
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr);
+ return Error ("breakpoint not found");
+ }
+
+ // Enable it.
+ return iter->second->Enable ();
+}
+
+Error
+NativeBreakpointList::DisableBreakpoint (lldb::addr_t addr)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ Mutex::Locker locker (m_mutex);
+
+ // Ensure we have said breakpoint.
+ auto iter = m_breakpoints.find (addr);
+ if (iter == m_breakpoints.end ())
+ {
+ // Not found!
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr);
+ return Error ("breakpoint not found");
+ }
+
+ // Disable it.
+ return iter->second->Disable ();
+}
+
+Error
+NativeBreakpointList::GetBreakpoint (lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ Mutex::Locker locker (m_mutex);
+
+ // Ensure we have said breakpoint.
+ auto iter = m_breakpoints.find (addr);
+ if (iter == m_breakpoints.end ())
+ {
+ // Not found!
+ breakpoint_sp.reset ();
+ return Error ("breakpoint not found");
+ }
+
+ // Disable it.
+ breakpoint_sp = iter->second;
+ return Error ();
+}
+
diff --git a/source/Host/common/NativeBreakpointList.h b/source/Host/common/NativeBreakpointList.h
new file mode 100644
index 000000000000..51617330d075
--- /dev/null
+++ b/source/Host/common/NativeBreakpointList.h
@@ -0,0 +1,53 @@
+//===-- NativeBreakpointList.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_NativeBreakpointList_h_
+#define liblldb_NativeBreakpointList_h_
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Mutex.h"
+// #include "lldb/Host/NativeBreakpoint.h"
+
+#include <functional>
+#include <map>
+
+namespace lldb_private
+{
+ class NativeBreakpointList
+ {
+ public:
+ typedef std::function<Error (lldb::addr_t addr, size_t size_hint, bool hardware, NativeBreakpointSP &breakpoint_sp)> CreateBreakpointFunc;
+
+ NativeBreakpointList ();
+
+ Error
+ AddRef (lldb::addr_t addr, size_t size_hint, bool hardware, CreateBreakpointFunc create_func);
+
+ Error
+ DecRef (lldb::addr_t addr);
+
+ Error
+ EnableBreakpoint (lldb::addr_t addr);
+
+ Error
+ DisableBreakpoint (lldb::addr_t addr);
+
+ Error
+ GetBreakpoint (lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp);
+
+ private:
+ typedef std::map<lldb::addr_t, NativeBreakpointSP> BreakpointMap;
+
+ Mutex m_mutex;
+ BreakpointMap m_breakpoints;
+ };
+}
+
+#endif // ifndef liblldb_NativeBreakpointList_h_
diff --git a/source/Host/common/NativeProcessProtocol.cpp b/source/Host/common/NativeProcessProtocol.cpp
new file mode 100644
index 000000000000..b7a77266c58c
--- /dev/null
+++ b/source/Host/common/NativeProcessProtocol.cpp
@@ -0,0 +1,412 @@
+//===-- NativeProcessProtocol.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessProtocol.h"
+
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Target/NativeRegisterContext.h"
+
+#include "NativeThreadProtocol.h"
+#include "SoftwareBreakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// -----------------------------------------------------------------------------
+// NativeProcessProtocol Members
+// -----------------------------------------------------------------------------
+
+NativeProcessProtocol::NativeProcessProtocol (lldb::pid_t pid) :
+ m_pid (pid),
+ m_threads (),
+ m_current_thread_id (LLDB_INVALID_THREAD_ID),
+ m_threads_mutex (Mutex::eMutexTypeRecursive),
+ m_state (lldb::eStateInvalid),
+ m_state_mutex (Mutex::eMutexTypeRecursive),
+ m_exit_type (eExitTypeInvalid),
+ m_exit_status (0),
+ m_exit_description (),
+ m_delegates_mutex (Mutex::eMutexTypeRecursive),
+ m_delegates (),
+ m_breakpoint_list (),
+ m_terminal_fd (-1),
+ m_stop_id (0)
+{
+}
+
+lldb_private::Error
+NativeProcessProtocol::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info)
+{
+ // Default: not implemented.
+ return Error ("not implemented");
+}
+
+bool
+NativeProcessProtocol::GetExitStatus (ExitType *exit_type, int *status, std::string &exit_description)
+{
+ if (m_state == lldb::eStateExited)
+ {
+ *exit_type = m_exit_type;
+ *status = m_exit_status;
+ exit_description = m_exit_description;
+ return true;
+ }
+
+ *status = 0;
+ return false;
+}
+
+bool
+NativeProcessProtocol::SetExitStatus (ExitType exit_type, int status, const char *exit_description, bool bNotifyStateChange)
+{
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessProtocol::%s(%d, %d, %s, %s) called",
+ __FUNCTION__,
+ exit_type,
+ status,
+ exit_description ? exit_description : "nullptr",
+ bNotifyStateChange ? "true" : "false");
+
+ // Exit status already set
+ if (m_state == lldb::eStateExited)
+ {
+ if (log)
+ log->Printf ("NativeProcessProtocol::%s exit status already set to %d, ignoring new set to %d", __FUNCTION__, m_exit_status, status);
+ return false;
+ }
+
+ m_state = lldb::eStateExited;
+
+ m_exit_type = exit_type;
+ m_exit_status = status;
+ if (exit_description && exit_description[0])
+ m_exit_description = exit_description;
+ else
+ m_exit_description.clear();
+
+ if (bNotifyStateChange)
+ SynchronouslyNotifyProcessStateChanged (lldb::eStateExited);
+
+ return true;
+}
+
+NativeThreadProtocolSP
+NativeProcessProtocol::GetThreadAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (m_threads_mutex);
+ if (idx < m_threads.size ())
+ return m_threads[idx];
+ return NativeThreadProtocolSP ();
+}
+
+NativeThreadProtocolSP
+NativeProcessProtocol::GetThreadByID (lldb::tid_t tid)
+{
+ Mutex::Locker locker (m_threads_mutex);
+ for (auto thread_sp : m_threads)
+ {
+ if (thread_sp->GetID() == tid)
+ return thread_sp;
+ }
+ return NativeThreadProtocolSP ();
+}
+
+bool
+NativeProcessProtocol::IsAlive () const
+{
+ return m_state != eStateDetached
+ && m_state != eStateExited
+ && m_state != eStateInvalid
+ && m_state != eStateUnloaded;
+}
+
+bool
+NativeProcessProtocol::GetByteOrder (lldb::ByteOrder &byte_order) const
+{
+ ArchSpec process_arch;
+ if (!GetArchitecture (process_arch))
+ return false;
+ byte_order = process_arch.GetByteOrder ();
+ return true;
+}
+
+uint32_t
+NativeProcessProtocol::GetMaxWatchpoints () const
+{
+ // This default implementation will return the number of
+ // *hardware* breakpoints available. MacOSX and other OS
+ // implementations that support software breakpoints will want to
+ // override this correctly for their implementation.
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // get any thread
+ NativeThreadProtocolSP thread_sp (const_cast<NativeProcessProtocol*> (this)->GetThreadAtIndex (0));
+ if (!thread_sp)
+ {
+ if (log)
+ log->Warning ("NativeProcessProtocol::%s (): failed to find a thread to grab a NativeRegisterContext!", __FUNCTION__);
+ return 0;
+ }
+
+ NativeRegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext ());
+ if (!reg_ctx_sp)
+ {
+ if (log)
+ log->Warning ("NativeProcessProtocol::%s (): failed to get a RegisterContextNativeProcess from the first thread!", __FUNCTION__);
+ return 0;
+ }
+
+ return reg_ctx_sp->NumSupportedHardwareWatchpoints ();
+}
+
+Error
+NativeProcessProtocol::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware)
+{
+ // This default implementation assumes setting the watchpoint for
+ // the process will require setting the watchpoint for each of the
+ // threads. Furthermore, it will track watchpoints set for the
+ // process and will add them to each thread that is attached to
+ // via the (FIXME implement) OnThreadAttached () method.
+
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // FIXME save the watchpoint on the set of process watchpoint vars
+ // so we can add them to a thread each time a new thread is registered.
+
+ // Update the thread list
+ UpdateThreads ();
+
+ // Keep track of the threads we successfully set the watchpoint
+ // for. If one of the thread watchpoint setting operations fails,
+ // back off and remove the watchpoint for all the threads that
+ // were successfully set so we get back to a consistent state.
+ std::vector<NativeThreadProtocolSP> watchpoint_established_threads;
+
+ // Tell each thread to set a watchpoint. In the event that
+ // hardware watchpoints are requested but the SetWatchpoint fails,
+ // try to set a software watchpoint as a fallback. It's
+ // conceivable that if there are more threads than hardware
+ // watchpoints available, some of the threads will fail to set
+ // hardware watchpoints while software ones may be available.
+ Mutex::Locker locker (m_threads_mutex);
+ for (auto thread_sp : m_threads)
+ {
+ assert (thread_sp && "thread list should not have a NULL thread!");
+ if (!thread_sp)
+ continue;
+
+ Error thread_error = thread_sp->SetWatchpoint (addr, size, watch_flags, hardware);
+ if (thread_error.Fail () && hardware)
+ {
+ // Try software watchpoints since we failed on hardware watchpoint setting
+ // and we may have just run out of hardware watchpoints.
+ thread_error = thread_sp->SetWatchpoint (addr, size, watch_flags, false);
+ if (thread_error.Success ())
+ {
+ if (log)
+ log->Warning ("hardware watchpoint requested but software watchpoint set");
+ }
+ }
+
+ if (thread_error.Success ())
+ {
+ // Remember that we set this watchpoint successfully in
+ // case we need to clear it later.
+ watchpoint_established_threads.push_back (thread_sp);
+ }
+ else
+ {
+ // Unset the watchpoint for each thread we successfully
+ // set so that we get back to a consistent state of "not
+ // set" for the watchpoint.
+ for (auto unwatch_thread_sp : watchpoint_established_threads)
+ {
+ Error remove_error = unwatch_thread_sp->RemoveWatchpoint (addr);
+ if (remove_error.Fail () && log)
+ {
+ log->Warning ("NativeProcessProtocol::%s (): RemoveWatchpoint failed for pid=%" PRIu64 ", tid=%" PRIu64 ": %s",
+ __FUNCTION__, GetID (), unwatch_thread_sp->GetID (), remove_error.AsCString ());
+ }
+ }
+
+ return thread_error;
+ }
+ }
+ return Error ();
+}
+
+Error
+NativeProcessProtocol::RemoveWatchpoint (lldb::addr_t addr)
+{
+ // FIXME remove the watchpoint on the set of process watchpoint vars
+ // so we can add them to a thread each time a new thread is registered.
+
+ // Update the thread list
+ UpdateThreads ();
+
+ Error overall_error;
+
+ Mutex::Locker locker (m_threads_mutex);
+ for (auto thread_sp : m_threads)
+ {
+ assert (thread_sp && "thread list should not have a NULL thread!");
+ if (!thread_sp)
+ continue;
+
+ const Error thread_error = thread_sp->RemoveWatchpoint (addr);
+ if (thread_error.Fail ())
+ {
+ // Keep track of the first thread error if any threads
+ // fail. We want to try to remove the watchpoint from
+ // every thread, though, even if one or more have errors.
+ if (!overall_error.Fail ())
+ overall_error = thread_error;
+ }
+ }
+ return overall_error;
+}
+
+bool
+NativeProcessProtocol::RegisterNativeDelegate (NativeDelegate &native_delegate)
+{
+ Mutex::Locker locker (m_delegates_mutex);
+ if (std::find (m_delegates.begin (), m_delegates.end (), &native_delegate) != m_delegates.end ())
+ return false;
+
+ m_delegates.push_back (&native_delegate);
+ native_delegate.InitializeDelegate (this);
+ return true;
+}
+
+bool
+NativeProcessProtocol::UnregisterNativeDelegate (NativeDelegate &native_delegate)
+{
+ Mutex::Locker locker (m_delegates_mutex);
+
+ const auto initial_size = m_delegates.size ();
+ m_delegates.erase (remove (m_delegates.begin (), m_delegates.end (), &native_delegate), m_delegates.end ());
+
+ // We removed the delegate if the count of delegates shrank after
+ // removing all copies of the given native_delegate from the vector.
+ return m_delegates.size () < initial_size;
+}
+
+void
+NativeProcessProtocol::SynchronouslyNotifyProcessStateChanged (lldb::StateType state)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ Mutex::Locker locker (m_delegates_mutex);
+ for (auto native_delegate: m_delegates)
+ native_delegate->ProcessStateChanged (this, state);
+
+ if (log)
+ {
+ if (!m_delegates.empty ())
+ {
+ log->Printf ("NativeProcessProtocol::%s: sent state notification [%s] from process %" PRIu64,
+ __FUNCTION__, lldb_private::StateAsCString (state), GetID ());
+ }
+ else
+ {
+ log->Printf ("NativeProcessProtocol::%s: would send state notification [%s] from process %" PRIu64 ", but no delegates",
+ __FUNCTION__, lldb_private::StateAsCString (state), GetID ());
+ }
+ }
+}
+
+void
+NativeProcessProtocol::NotifyDidExec ()
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessProtocol::%s - preparing to call delegates", __FUNCTION__);
+
+ {
+ Mutex::Locker locker (m_delegates_mutex);
+ for (auto native_delegate: m_delegates)
+ native_delegate->DidExec (this);
+ }
+}
+
+
+Error
+NativeProcessProtocol::SetSoftwareBreakpoint (lldb::addr_t addr, uint32_t size_hint)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeProcessProtocol::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ return m_breakpoint_list.AddRef (addr, size_hint, false,
+ [this] (lldb::addr_t addr, size_t size_hint, bool /* hardware */, NativeBreakpointSP &breakpoint_sp)->Error
+ { return SoftwareBreakpoint::CreateSoftwareBreakpoint (*this, addr, size_hint, breakpoint_sp); });
+}
+
+Error
+NativeProcessProtocol::RemoveBreakpoint (lldb::addr_t addr)
+{
+ return m_breakpoint_list.DecRef (addr);
+}
+
+Error
+NativeProcessProtocol::EnableBreakpoint (lldb::addr_t addr)
+{
+ return m_breakpoint_list.EnableBreakpoint (addr);
+}
+
+Error
+NativeProcessProtocol::DisableBreakpoint (lldb::addr_t addr)
+{
+ return m_breakpoint_list.DisableBreakpoint (addr);
+}
+
+lldb::StateType
+NativeProcessProtocol::GetState () const
+{
+ Mutex::Locker locker (m_state_mutex);
+ return m_state;
+}
+
+void
+NativeProcessProtocol::SetState (lldb::StateType state, bool notify_delegates)
+{
+ Mutex::Locker locker (m_state_mutex);
+ m_state = state;
+
+ if (StateIsStoppedState (state, false))
+ {
+ ++m_stop_id;
+
+ // Give process a chance to do any stop id bump processing, such as
+ // clearing cached data that is invalidated each time the process runs.
+ // Note if/when we support some threads running, we'll end up needing
+ // to manage this per thread and per process.
+ DoStopIDBumped (m_stop_id);
+ }
+
+ // Optionally notify delegates of the state change.
+ if (notify_delegates)
+ SynchronouslyNotifyProcessStateChanged (state);
+}
+
+uint32_t NativeProcessProtocol::GetStopID () const
+{
+ Mutex::Locker locker (m_state_mutex);
+ return m_stop_id;
+}
+
+void
+NativeProcessProtocol::DoStopIDBumped (uint32_t /* newBumpId */)
+{
+ // Default implementation does nothing.
+}
diff --git a/source/Host/common/NativeProcessProtocol.h b/source/Host/common/NativeProcessProtocol.h
new file mode 100644
index 000000000000..035a264e172e
--- /dev/null
+++ b/source/Host/common/NativeProcessProtocol.h
@@ -0,0 +1,333 @@
+//===-- NativeProcessProtocol.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_NativeProcessProtocol_h_
+#define liblldb_NativeProcessProtocol_h_
+
+#include <vector>
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/lldb-types.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Mutex.h"
+
+#include "NativeBreakpointList.h"
+
+namespace lldb_private
+{
+ class MemoryRegionInfo;
+ class ResumeActionList;
+
+ //------------------------------------------------------------------
+ // NativeProcessProtocol
+ //------------------------------------------------------------------
+ class NativeProcessProtocol :
+ public std::enable_shared_from_this<NativeProcessProtocol>
+ {
+ friend class SoftwareBreakpoint;
+
+ public:
+ static NativeProcessProtocol *
+ CreateInstance (lldb::pid_t pid);
+
+ // lldb_private::Host calls should be used to launch a process for debugging, and
+ // then the process should be attached to. When attaching to a process
+ // lldb_private::Host calls should be used to locate the process to attach to,
+ // and then this function should be called.
+ NativeProcessProtocol (lldb::pid_t pid);
+
+ public:
+ virtual ~NativeProcessProtocol ()
+ {
+ }
+
+ virtual Error
+ Resume (const ResumeActionList &resume_actions) = 0;
+
+ virtual Error
+ Halt () = 0;
+
+ virtual Error
+ Detach () = 0;
+
+ //------------------------------------------------------------------
+ /// Sends a process a UNIX signal \a signal.
+ ///
+ /// Implementer note: the WillSignal ()/DidSignal () calls
+ /// from the Process class are not replicated here since no
+ /// concrete classes implemented any behavior for those and
+ /// put all the work in DoSignal (...).
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ Signal (int signo) = 0;
+
+ virtual Error
+ Kill () = 0;
+
+ //----------------------------------------------------------------------
+ // Memory and memory region functions
+ //----------------------------------------------------------------------
+
+ virtual Error
+ GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info);
+
+ virtual Error
+ ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read) = 0;
+
+ virtual Error
+ WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written) = 0;
+
+ virtual Error
+ AllocateMemory (lldb::addr_t size, uint32_t permissions, lldb::addr_t &addr) = 0;
+
+ virtual Error
+ DeallocateMemory (lldb::addr_t addr) = 0;
+
+ virtual lldb::addr_t
+ GetSharedLibraryInfoAddress () = 0;
+
+ virtual bool
+ IsAlive () const;
+
+ virtual size_t
+ UpdateThreads () = 0;
+
+ virtual bool
+ GetArchitecture (ArchSpec &arch) const = 0;
+
+ //----------------------------------------------------------------------
+ // Breakpoint functions
+ //----------------------------------------------------------------------
+ virtual Error
+ SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware) = 0;
+
+ virtual Error
+ RemoveBreakpoint (lldb::addr_t addr);
+
+ virtual Error
+ EnableBreakpoint (lldb::addr_t addr);
+
+ virtual Error
+ DisableBreakpoint (lldb::addr_t addr);
+
+ //----------------------------------------------------------------------
+ // Watchpoint functions
+ //----------------------------------------------------------------------
+ virtual uint32_t
+ GetMaxWatchpoints () const;
+
+ virtual Error
+ SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware);
+
+ virtual Error
+ RemoveWatchpoint (lldb::addr_t addr);
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ lldb::pid_t
+ GetID() const
+ {
+ return m_pid;
+ }
+
+ lldb::StateType
+ GetState () const;
+
+ bool
+ IsRunning () const
+ {
+ return m_state == lldb::eStateRunning || IsStepping();
+ }
+
+ bool
+ IsStepping () const
+ {
+ return m_state == lldb::eStateStepping;
+ }
+
+ bool
+ CanResume () const
+ {
+ return m_state == lldb::eStateStopped;
+ }
+
+ bool
+ GetByteOrder (lldb::ByteOrder &byte_order) const;
+
+ //----------------------------------------------------------------------
+ // Exit Status
+ //----------------------------------------------------------------------
+ virtual bool
+ GetExitStatus (lldb_private::ExitType *exit_type, int *status, std::string &exit_description);
+
+ virtual bool
+ SetExitStatus (lldb_private::ExitType exit_type, int status, const char *exit_description, bool bNotifyStateChange);
+
+ //----------------------------------------------------------------------
+ // Access to threads
+ //----------------------------------------------------------------------
+ NativeThreadProtocolSP
+ GetThreadAtIndex (uint32_t idx);
+
+ NativeThreadProtocolSP
+ GetThreadByID (lldb::tid_t tid);
+
+ void
+ SetCurrentThreadID (lldb::tid_t tid)
+ {
+ m_current_thread_id = tid;
+ }
+
+ lldb::tid_t
+ GetCurrentThreadID ()
+ {
+ return m_current_thread_id;
+ }
+
+ NativeThreadProtocolSP
+ GetCurrentThread ()
+ {
+ return GetThreadByID (m_current_thread_id);
+ }
+
+ //----------------------------------------------------------------------
+ // Access to inferior stdio
+ //----------------------------------------------------------------------
+ virtual
+ int GetTerminalFileDescriptor ()
+ {
+ return m_terminal_fd;
+ }
+
+ //----------------------------------------------------------------------
+ // Stop id interface
+ //----------------------------------------------------------------------
+
+ uint32_t
+ GetStopID () const;
+
+ // ---------------------------------------------------------------------
+ // Callbacks for low-level process state changes
+ // ---------------------------------------------------------------------
+ class NativeDelegate
+ {
+ public:
+ virtual
+ ~NativeDelegate () {}
+
+ virtual void
+ InitializeDelegate (NativeProcessProtocol *process) = 0;
+
+ virtual void
+ ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state) = 0;
+
+ virtual void
+ DidExec (NativeProcessProtocol *process) = 0;
+ };
+
+ //------------------------------------------------------------------
+ /// Register a native delegate.
+ ///
+ /// Clients can register nofication callbacks by passing in a
+ /// NativeDelegate impl and passing it into this function.
+ ///
+ /// Note: it is required that the lifetime of the
+ /// native_delegate outlive the NativeProcessProtocol.
+ ///
+ /// @param[in] native_delegate
+ /// A NativeDelegate impl to be called when certain events
+ /// happen within the NativeProcessProtocol or related threads.
+ ///
+ /// @return
+ /// true if the delegate was registered successfully;
+ /// false if the delegate was already registered.
+ ///
+ /// @see NativeProcessProtocol::NativeDelegate.
+ //------------------------------------------------------------------
+ bool
+ RegisterNativeDelegate (NativeDelegate &native_delegate);
+
+ //------------------------------------------------------------------
+ /// Unregister a native delegate previously registered.
+ ///
+ /// @param[in] native_delegate
+ /// A NativeDelegate impl previously registered with this process.
+ ///
+ /// @return Returns \b true if the NativeDelegate was
+ /// successfully removed from the process, \b false otherwise.
+ ///
+ /// @see NativeProcessProtocol::NativeDelegate
+ //------------------------------------------------------------------
+ bool
+ UnregisterNativeDelegate (NativeDelegate &native_delegate);
+
+ protected:
+ lldb::pid_t m_pid;
+
+ std::vector<NativeThreadProtocolSP> m_threads;
+ lldb::tid_t m_current_thread_id;
+ mutable Mutex m_threads_mutex;
+
+ lldb::StateType m_state;
+ mutable Mutex m_state_mutex;
+
+ lldb_private::ExitType m_exit_type;
+ int m_exit_status;
+ std::string m_exit_description;
+ Mutex m_delegates_mutex;
+ std::vector<NativeDelegate*> m_delegates;
+ NativeBreakpointList m_breakpoint_list;
+ int m_terminal_fd;
+ uint32_t m_stop_id;
+
+ // -----------------------------------------------------------
+ // Internal interface for state handling
+ // -----------------------------------------------------------
+ void
+ SetState (lldb::StateType state, bool notify_delegates = true);
+
+ // Derived classes need not impelment this. It can be used as a
+ // hook to clear internal caches that should be invalidated when
+ // stop ids change.
+ //
+ // Note this function is called with the state mutex obtained
+ // by the caller.
+ virtual void
+ DoStopIDBumped (uint32_t newBumpId);
+
+ // -----------------------------------------------------------
+ // Internal interface for software breakpoints
+ // -----------------------------------------------------------
+ Error
+ SetSoftwareBreakpoint (lldb::addr_t addr, uint32_t size_hint);
+
+ virtual Error
+ GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, size_t &actual_opcode_size, const uint8_t *&trap_opcode_bytes) = 0;
+
+ // -----------------------------------------------------------
+ /// Notify the delegate that an exec occurred.
+ ///
+ /// Provide a mechanism for a delegate to clear out any exec-
+ /// sensitive data.
+ // -----------------------------------------------------------
+ void
+ NotifyDidExec ();
+
+ private:
+
+ void
+ SynchronouslyNotifyProcessStateChanged (lldb::StateType state);
+ };
+}
+
+#endif // #ifndef liblldb_NativeProcessProtocol_h_
diff --git a/source/Host/common/NativeThreadProtocol.cpp b/source/Host/common/NativeThreadProtocol.cpp
new file mode 100644
index 000000000000..6cef5b1fa2d2
--- /dev/null
+++ b/source/Host/common/NativeThreadProtocol.cpp
@@ -0,0 +1,97 @@
+//===-- NativeThreadProtocol.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeThreadProtocol.h"
+
+#include "NativeProcessProtocol.h"
+#include "lldb/Target/NativeRegisterContext.h"
+#include "SoftwareBreakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+NativeThreadProtocol::NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid) :
+ m_process_wp (process->shared_from_this ()),
+ m_tid (tid)
+{
+}
+
+Error
+NativeThreadProtocol::ReadRegister (uint32_t reg, RegisterValue &reg_value)
+{
+ NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+ if (!register_context_sp)
+ return Error ("no register context");
+
+ const RegisterInfo *const reg_info = register_context_sp->GetRegisterInfoAtIndex (reg);
+ if (!reg_info)
+ return Error ("no register info for reg num %" PRIu32, reg);
+
+ return register_context_sp->ReadRegister (reg_info, reg_value);;
+}
+
+Error
+NativeThreadProtocol::WriteRegister (uint32_t reg, const RegisterValue &reg_value)
+{
+ NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+ if (!register_context_sp)
+ return Error ("no register context");
+
+ const RegisterInfo *const reg_info = register_context_sp->GetRegisterInfoAtIndex (reg);
+ if (!reg_info)
+ return Error ("no register info for reg num %" PRIu32, reg);
+
+ return register_context_sp->WriteRegister (reg_info, reg_value);
+}
+
+Error
+NativeThreadProtocol::SaveAllRegisters (lldb::DataBufferSP &data_sp)
+{
+ NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+ if (!register_context_sp)
+ return Error ("no register context");
+ return register_context_sp->WriteAllRegisterValues (data_sp);
+}
+
+Error
+NativeThreadProtocol::RestoreAllRegisters (lldb::DataBufferSP &data_sp)
+{
+ NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+ if (!register_context_sp)
+ return Error ("no register context");
+ return register_context_sp->ReadAllRegisterValues (data_sp);
+}
+
+NativeProcessProtocolSP
+NativeThreadProtocol::GetProcess ()
+{
+ return m_process_wp.lock ();
+}
+
+uint32_t
+NativeThreadProtocol::TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const
+{
+ // Default: no translation. Do the real translation where there
+ // is access to the host signal numbers.
+ switch (stop_info.reason)
+ {
+ case eStopReasonSignal:
+ return stop_info.details.signal.signo;
+ break;
+
+ case eStopReasonException:
+ // FIXME verify the way to specify pass-thru here.
+ return static_cast<uint32_t> (stop_info.details.exception.type);
+ break;
+
+ default:
+ assert (0 && "unexpected stop_info.reason found");
+ return 0;
+ }
+}
diff --git a/source/Host/common/NativeThreadProtocol.h b/source/Host/common/NativeThreadProtocol.h
new file mode 100644
index 000000000000..9b404be500b9
--- /dev/null
+++ b/source/Host/common/NativeThreadProtocol.h
@@ -0,0 +1,85 @@
+//===-- NativeThreadProtocol.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_NativeThreadProtocol_h_
+#define liblldb_NativeThreadProtocol_h_
+
+#include <memory>
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/lldb-types.h"
+#include "lldb/Host/Debug.h"
+
+namespace lldb_private
+{
+ //------------------------------------------------------------------
+ // NativeThreadProtocol
+ //------------------------------------------------------------------
+ class NativeThreadProtocol:
+ public std::enable_shared_from_this<NativeThreadProtocol>
+ {
+ public:
+ NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid);
+
+ virtual ~NativeThreadProtocol()
+ {
+ }
+
+ virtual const char *
+ GetName() = 0;
+
+ virtual lldb::StateType
+ GetState () = 0;
+
+ virtual NativeRegisterContextSP
+ GetRegisterContext () = 0;
+
+ virtual Error
+ ReadRegister (uint32_t reg, RegisterValue &reg_value);
+
+ virtual Error
+ WriteRegister (uint32_t reg, const RegisterValue &reg_value);
+
+ virtual Error
+ SaveAllRegisters (lldb::DataBufferSP &data_sp);
+
+ virtual Error
+ RestoreAllRegisters (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ GetStopReason (ThreadStopInfo &stop_info) = 0;
+
+ virtual uint32_t
+ TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const;
+
+ lldb::tid_t
+ GetID() const
+ {
+ return m_tid;
+ }
+
+ NativeProcessProtocolSP
+ GetProcess ();
+
+ // ---------------------------------------------------------------------
+ // Thread-specific watchpoints
+ // ---------------------------------------------------------------------
+ virtual Error
+ SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) = 0;
+
+ virtual Error
+ RemoveWatchpoint (lldb::addr_t addr) = 0;
+
+ protected:
+ NativeProcessProtocolWP m_process_wp;
+ lldb::tid_t m_tid;
+ };
+}
+
+#endif // #ifndef liblldb_NativeThreadProtocol_h_
diff --git a/source/Host/common/OptionParser.cpp b/source/Host/common/OptionParser.cpp
index cf133597cb84..a91e764bfe3b 100644
--- a/source/Host/common/OptionParser.cpp
+++ b/source/Host/common/OptionParser.cpp
@@ -8,11 +8,10 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/OptionParser.h"
-
-#if (!defined( _MSC_VER ) && defined( _WIN32 ))
-#define _BSD_SOURCE // Required so that getopt.h defines optreset
-#endif
#include "lldb/Host/HostGetOpt.h"
+#include "lldb/lldb-private-types.h"
+
+#include <vector>
using namespace lldb_private;
@@ -40,7 +39,19 @@ OptionParser::Parse (int argc,
const Option *longopts,
int *longindex)
{
- return getopt_long_only(argc, argv, optstring, (const option*)longopts, longindex);
+ std::vector<option> opts;
+ while (longopts->definition != nullptr)
+ {
+ option opt;
+ opt.flag = longopts->flag;
+ opt.val = longopts->val;
+ opt.name = longopts->definition->long_option;
+ opt.has_arg = longopts->definition->option_has_arg;
+ opts.push_back(opt);
+ ++longopts;
+ }
+ opts.push_back(option());
+ return getopt_long_only(argc, argv, optstring, &opts[0], longindex);
}
char*
diff --git a/source/Host/common/Pipe.cpp b/source/Host/common/Pipe.cpp
new file mode 100644
index 000000000000..4db0e32c93b7
--- /dev/null
+++ b/source/Host/common/Pipe.cpp
@@ -0,0 +1,171 @@
+//===-- Pipe.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/Host/Pipe.h"
+
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#else
+#include <unistd.h>
+#endif
+
+using namespace lldb_private;
+
+int Pipe::kInvalidDescriptor = -1;
+
+enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
+
+Pipe::Pipe()
+{
+ m_fds[READ] = Pipe::kInvalidDescriptor;
+ m_fds[WRITE] = Pipe::kInvalidDescriptor;
+}
+
+Pipe::~Pipe()
+{
+ Close();
+}
+
+bool
+Pipe::Open()
+{
+ if (IsValid())
+ return true;
+
+#ifdef _WIN32
+ if (::_pipe(m_fds, 256, O_BINARY) == 0)
+ return true;
+#else
+ if (::pipe(m_fds) == 0)
+ return true;
+#endif
+ m_fds[READ] = Pipe::kInvalidDescriptor;
+ m_fds[WRITE] = Pipe::kInvalidDescriptor;
+ return false;
+}
+
+int
+Pipe::GetReadFileDescriptor() const
+{
+ return m_fds[READ];
+}
+
+int
+Pipe::GetWriteFileDescriptor() const
+{
+ return m_fds[WRITE];
+}
+
+int
+Pipe::ReleaseReadFileDescriptor()
+{
+ const int fd = m_fds[READ];
+ m_fds[READ] = Pipe::kInvalidDescriptor;
+ return fd;
+}
+
+int
+Pipe::ReleaseWriteFileDescriptor()
+{
+ const int fd = m_fds[WRITE];
+ m_fds[WRITE] = Pipe::kInvalidDescriptor;
+ return fd;
+}
+
+void
+Pipe::Close()
+{
+ CloseReadFileDescriptor();
+ CloseWriteFileDescriptor();
+}
+
+bool
+Pipe::ReadDescriptorIsValid() const
+{
+ return m_fds[READ] != Pipe::kInvalidDescriptor;
+}
+
+bool
+Pipe::WriteDescriptorIsValid() const
+{
+ return m_fds[WRITE] != Pipe::kInvalidDescriptor;
+}
+
+bool
+Pipe::IsValid() const
+{
+ return ReadDescriptorIsValid() && WriteDescriptorIsValid();
+}
+
+bool
+Pipe::CloseReadFileDescriptor()
+{
+ if (ReadDescriptorIsValid())
+ {
+ int err;
+#ifdef _WIN32
+ err = _close(m_fds[READ]);
+#else
+ err = close(m_fds[READ]);
+#endif
+ m_fds[READ] = Pipe::kInvalidDescriptor;
+ return err == 0;
+ }
+ return true;
+}
+
+bool
+Pipe::CloseWriteFileDescriptor()
+{
+ if (WriteDescriptorIsValid())
+ {
+ int err;
+#ifdef _WIN32
+ err = _close(m_fds[WRITE]);
+#else
+ err = close(m_fds[WRITE]);
+#endif
+ m_fds[WRITE] = Pipe::kInvalidDescriptor;
+ return err == 0;
+ }
+ return true;
+}
+
+
+size_t
+Pipe::Read (void *buf, size_t num_bytes)
+{
+ if (ReadDescriptorIsValid())
+ {
+ const int fd = GetReadFileDescriptor();
+#ifdef _WIN32
+ return _read (fd, (char *)buf, num_bytes);
+#else
+ return read (fd, buf, num_bytes);
+#endif
+ }
+ return 0; // Return 0 since errno won't be set if we didn't call read
+}
+
+size_t
+Pipe::Write (const void *buf, size_t num_bytes)
+{
+ if (WriteDescriptorIsValid())
+ {
+ const int fd = GetWriteFileDescriptor();
+#ifdef _WIN32
+ return _write (fd, (char *)buf, num_bytes);
+#else
+ return write (fd, buf, num_bytes);
+#endif
+ }
+ return 0; // Return 0 since errno won't be set if we didn't call write
+}
+
diff --git a/source/Host/common/Socket.cpp b/source/Host/common/Socket.cpp
new file mode 100644
index 000000000000..31e3228497ec
--- /dev/null
+++ b/source/Host/common/Socket.cpp
@@ -0,0 +1,662 @@
+//===-- Socket.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/Host/Socket.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/SocketAddress.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Interpreter/Args.h"
+
+#ifndef LLDB_DISABLE_POSIX
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+#if defined(_WIN32)
+typedef const char * set_socket_option_arg_type;
+typedef char * get_socket_option_arg_type;
+const NativeSocket Socket::kInvalidSocketValue = INVALID_SOCKET;
+#else // #if defined(_WIN32)
+typedef const void * set_socket_option_arg_type;
+typedef void * get_socket_option_arg_type;
+const NativeSocket Socket::kInvalidSocketValue = -1;
+#endif // #if defined(_WIN32)
+
+Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close)
+ : IOObject(eFDTypeSocket, should_close)
+ , m_protocol(protocol)
+ , m_socket(socket)
+{
+
+}
+
+Socket::~Socket()
+{
+ Close();
+}
+
+Error Socket::TcpConnect(llvm::StringRef host_and_port, Socket *&socket)
+{
+ // Store the result in a unique_ptr in case we error out, the memory will get correctly freed.
+ std::unique_ptr<Socket> final_socket;
+ NativeSocket sock = kInvalidSocketValue;
+ Error error;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST));
+ if (log)
+ log->Printf ("Socket::TcpConnect (host/port = %s)", host_and_port.data());
+
+ std::string host_str;
+ std::string port_str;
+ int32_t port = INT32_MIN;
+ if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, &error))
+ return error;
+
+ // Create the socket
+ sock = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sock == kInvalidSocketValue)
+ {
+ // TODO: On Windows, use WSAGetLastError().
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ // Since they both refer to the same socket descriptor, arbitrarily choose the send socket to
+ // be the owner.
+ final_socket.reset(new Socket(sock, ProtocolTcp, true));
+
+ // Enable local address reuse
+ final_socket->SetOption(SOL_SOCKET, SO_REUSEADDR, 1);
+
+ struct sockaddr_in sa;
+ ::memset (&sa, 0, sizeof (sa));
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons (port);
+
+ int inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr);
+
+ if (inet_pton_result <= 0)
+ {
+ struct hostent *host_entry = gethostbyname (host_str.c_str());
+ if (host_entry)
+ host_str = ::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list);
+ inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr);
+ if (inet_pton_result <= 0)
+ {
+ // TODO: On Windows, use WSAGetLastError()
+ if (inet_pton_result == -1)
+ error.SetErrorToErrno();
+ else
+ error.SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str());
+
+ return error;
+ }
+ }
+
+ if (-1 == ::connect (sock, (const struct sockaddr *)&sa, sizeof(sa)))
+ {
+ // TODO: On Windows, use WSAGetLastError()
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ // Keep our TCP packets coming without any delays.
+ final_socket->SetOption(IPPROTO_TCP, TCP_NODELAY, 1);
+ error.Clear();
+ socket = final_socket.release();
+ return error;
+}
+
+Error Socket::TcpListen(llvm::StringRef host_and_port, Socket *&socket, Predicate<uint16_t>* predicate)
+{
+ std::unique_ptr<Socket> listen_socket;
+ NativeSocket listen_sock = kInvalidSocketValue;
+ Error error;
+
+ const sa_family_t family = AF_INET;
+ const int socktype = SOCK_STREAM;
+ const int protocol = IPPROTO_TCP;
+ listen_sock = ::socket (family, socktype, protocol);
+ if (listen_sock == kInvalidSocketValue)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ listen_socket.reset(new Socket(listen_sock, ProtocolTcp, true));
+
+ // enable local address reuse
+ listen_socket->SetOption(SOL_SOCKET, SO_REUSEADDR, 1);
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("ConnectionFileDescriptor::SocketListen (%s)", host_and_port.data());
+
+ std::string host_str;
+ std::string port_str;
+ int32_t port = INT32_MIN;
+ if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, &error))
+ return error;
+
+ SocketAddress anyaddr;
+ if (anyaddr.SetToAnyAddress (family, port))
+ {
+ int err = ::bind (listen_sock, anyaddr, anyaddr.GetLength());
+ if (err == -1)
+ {
+ // TODO: On Windows, use WSAGetLastError()
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ err = ::listen (listen_sock, 1);
+ if (err == -1)
+ {
+ // TODO: On Windows, use WSAGetLastError()
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ // We were asked to listen on port zero which means we
+ // must now read the actual port that was given to us
+ // as port zero is a special code for "find an open port
+ // for me".
+ if (port == 0)
+ port = listen_socket->GetPortNumber();
+
+ // Set the port predicate since when doing a listen://<host>:<port>
+ // it often needs to accept the incoming connection which is a blocking
+ // system call. Allowing access to the bound port using a predicate allows
+ // us to wait for the port predicate to be set to a non-zero value from
+ // another thread in an efficient manor.
+ if (predicate)
+ predicate->SetValue(port, eBroadcastAlways);
+
+ socket = listen_socket.release();
+ }
+
+ return error;
+}
+
+Error Socket::BlockingAccept(llvm::StringRef host_and_port, Socket *&socket)
+{
+ Error error;
+ std::string host_str;
+ std::string port_str;
+ int32_t port;
+ if (!DecodeHostAndPort(host_and_port, host_str, port_str, port, &error))
+ return error;
+
+ const sa_family_t family = AF_INET;
+ const int socktype = SOCK_STREAM;
+ const int protocol = IPPROTO_TCP;
+ SocketAddress listen_addr;
+ if (host_str.empty())
+ listen_addr.SetToLocalhost(family, port);
+ else if (host_str.compare("*") == 0)
+ listen_addr.SetToAnyAddress(family, port);
+ else
+ {
+ if (!listen_addr.getaddrinfo(host_str.c_str(), port_str.c_str(), family, socktype, protocol))
+ {
+ error.SetErrorStringWithFormat("unable to resolve hostname '%s'", host_str.c_str());
+ return error;
+ }
+ }
+
+ bool accept_connection = false;
+ std::unique_ptr<Socket> accepted_socket;
+
+ // Loop until we are happy with our connection
+ while (!accept_connection)
+ {
+ struct sockaddr_in accept_addr;
+ ::memset (&accept_addr, 0, sizeof accept_addr);
+#if !(defined (__linux__) || defined(_WIN32))
+ accept_addr.sin_len = sizeof accept_addr;
+#endif
+ socklen_t accept_addr_len = sizeof accept_addr;
+
+ int sock = ::accept (this->GetNativeSocket(), (struct sockaddr *)&accept_addr, &accept_addr_len);
+
+ if (sock == kInvalidSocketValue)
+ {
+ // TODO: On Windows, use WSAGetLastError()
+ error.SetErrorToErrno();
+ break;
+ }
+
+ bool is_same_addr = true;
+#if !(defined(__linux__) || (defined(_WIN32)))
+ is_same_addr = (accept_addr_len == listen_addr.sockaddr_in().sin_len);
+#endif
+ if (is_same_addr)
+ is_same_addr = (accept_addr.sin_addr.s_addr == listen_addr.sockaddr_in().sin_addr.s_addr);
+
+ if (is_same_addr || (listen_addr.sockaddr_in().sin_addr.s_addr == INADDR_ANY))
+ {
+ accept_connection = true;
+ // Since both sockets have the same descriptor, arbitrarily choose the send
+ // socket to be the owner.
+ accepted_socket.reset(new Socket(sock, ProtocolTcp, true));
+ }
+ else
+ {
+ const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr;
+ const uint8_t *listen_ip = (const uint8_t *)&listen_addr.sockaddr_in().sin_addr.s_addr;
+ ::fprintf (stderr, "error: rejecting incoming connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)\n",
+ accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
+ listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
+ accepted_socket.reset();
+ }
+ }
+
+ if (!accepted_socket)
+ return error;
+
+ // Keep our TCP packets coming without any delays.
+ accepted_socket->SetOption (IPPROTO_TCP, TCP_NODELAY, 1);
+ error.Clear();
+ socket = accepted_socket.release();
+ return error;
+
+}
+
+Error Socket::UdpConnect(llvm::StringRef host_and_port, Socket *&send_socket, Socket *&recv_socket)
+{
+ std::unique_ptr<Socket> final_send_socket;
+ std::unique_ptr<Socket> final_recv_socket;
+ NativeSocket final_send_fd = kInvalidSocketValue;
+ NativeSocket final_recv_fd = kInvalidSocketValue;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("Socket::UdpConnect (host/port = %s)", host_and_port.data());
+
+ Error error;
+ std::string host_str;
+ std::string port_str;
+ int32_t port = INT32_MIN;
+ if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, &error))
+ return error;
+
+ // Setup the receiving end of the UDP connection on this localhost
+ // on port zero. After we bind to port zero we can read the port.
+ final_recv_fd = ::socket (AF_INET, SOCK_DGRAM, 0);
+ if (final_recv_fd == kInvalidSocketValue)
+ {
+ // Socket creation failed...
+ // TODO: On Windows, use WSAGetLastError().
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ final_recv_socket.reset(new Socket(final_recv_fd, ProtocolUdp, true));
+
+ // Socket was created, now lets bind to the requested port
+ SocketAddress addr;
+ addr.SetToAnyAddress (AF_INET, 0);
+
+ if (::bind (final_recv_fd, addr, addr.GetLength()) == -1)
+ {
+ // Bind failed...
+ // TODO: On Windows use WSAGetLastError()
+ error.SetErrorToErrno();
+ }
+ }
+
+ assert(error.Fail() == !(final_recv_socket && final_recv_socket->IsValid()));
+ if (error.Fail())
+ return error;
+
+ // At this point we have setup the receive port, now we need to
+ // setup the UDP send socket
+
+ struct addrinfo hints;
+ struct addrinfo *service_info_list = NULL;
+
+ ::memset (&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ int err = ::getaddrinfo (host_str.c_str(), port_str.c_str(), &hints, &service_info_list);
+ if (err != 0)
+ {
+ error.SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)",
+ host_str.c_str(),
+ port_str.c_str(),
+ err,
+ gai_strerror(err));
+ return error;
+ }
+
+ for (struct addrinfo *service_info_ptr = service_info_list;
+ service_info_ptr != NULL;
+ service_info_ptr = service_info_ptr->ai_next)
+ {
+ final_send_fd = ::socket (service_info_ptr->ai_family,
+ service_info_ptr->ai_socktype,
+ service_info_ptr->ai_protocol);
+
+ if (final_send_fd != kInvalidSocketValue)
+ {
+ final_send_socket.reset(new Socket(final_send_fd, ProtocolUdp, true));
+ final_send_socket->m_udp_send_sockaddr = service_info_ptr;
+ break;
+ }
+ else
+ continue;
+ }
+
+ :: freeaddrinfo (service_info_list);
+
+ if (final_send_fd == kInvalidSocketValue)
+ {
+ // TODO: On Windows, use WSAGetLastError().
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ send_socket = final_send_socket.release();
+ recv_socket = final_recv_socket.release();
+ error.Clear();
+ return error;
+}
+
+Error Socket::UnixDomainConnect(llvm::StringRef name, Socket *&socket)
+{
+ Error error;
+#ifndef LLDB_DISABLE_POSIX
+ std::unique_ptr<Socket> final_socket;
+
+ // Open the socket that was passed in as an option
+ struct sockaddr_un saddr_un;
+ int fd = ::socket (AF_UNIX, SOCK_STREAM, 0);
+ if (fd == kInvalidSocketValue)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ final_socket.reset(new Socket(fd, ProtocolUnixDomain, true));
+
+ saddr_un.sun_family = AF_UNIX;
+ ::strncpy(saddr_un.sun_path, name.data(), sizeof(saddr_un.sun_path) - 1);
+ saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
+ saddr_un.sun_len = SUN_LEN (&saddr_un);
+#endif
+
+ if (::connect (fd, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ socket = final_socket.release();
+#else
+ error.SetErrorString("Unix domain sockets are not supported on this platform.");
+#endif
+ return error;
+}
+
+Error Socket::UnixDomainAccept(llvm::StringRef name, Socket *&socket)
+{
+ Error error;
+#ifndef LLDB_DISABLE_POSIX
+ struct sockaddr_un saddr_un;
+ std::unique_ptr<Socket> listen_socket;
+ std::unique_ptr<Socket> final_socket;
+ NativeSocket listen_fd = kInvalidSocketValue;
+ NativeSocket socket_fd = kInvalidSocketValue;
+
+ listen_fd = ::socket (AF_UNIX, SOCK_STREAM, 0);
+ if (listen_fd == kInvalidSocketValue)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ listen_socket.reset(new Socket(listen_fd, ProtocolUnixDomain, true));
+
+ saddr_un.sun_family = AF_UNIX;
+ ::strncpy(saddr_un.sun_path, name.data(), sizeof(saddr_un.sun_path) - 1);
+ saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
+ saddr_un.sun_len = SUN_LEN (&saddr_un);
+#endif
+
+ FileSystem::Unlink(name.data());
+ bool success = false;
+ if (::bind (listen_fd, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0)
+ {
+ if (::listen (listen_fd, 5) == 0)
+ {
+ socket_fd = ::accept (listen_fd, NULL, 0);
+ if (socket_fd > 0)
+ {
+ final_socket.reset(new Socket(socket_fd, ProtocolUnixDomain, true));
+ success = true;
+ }
+ }
+ }
+
+ if (!success)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+ // We are done with the listen port
+ listen_socket.reset();
+
+ socket = final_socket.release();
+#else
+ error.SetErrorString("Unix domain sockets are not supported on this platform.");
+#endif
+ return error;
+}
+
+bool
+Socket::DecodeHostAndPort(llvm::StringRef host_and_port,
+ std::string &host_str,
+ std::string &port_str,
+ int32_t& port,
+ Error *error_ptr)
+{
+ static RegularExpression g_regex ("([^:]+):([0-9]+)");
+ RegularExpression::Match regex_match(2);
+ if (g_regex.Execute (host_and_port.data(), &regex_match))
+ {
+ if (regex_match.GetMatchAtIndex (host_and_port.data(), 1, host_str) &&
+ regex_match.GetMatchAtIndex (host_and_port.data(), 2, port_str))
+ {
+ port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN);
+ if (port != INT32_MIN)
+ {
+ if (error_ptr)
+ error_ptr->Clear();
+ return true;
+ }
+ }
+ }
+
+ // If this was unsuccessful, then check if it's simply a signed 32-bit integer, representing
+ // a port with an empty host.
+ host_str.clear();
+ port_str.clear();
+ port = Args::StringToSInt32(host_and_port.data(), INT32_MIN);
+ if (port != INT32_MIN)
+ {
+ port_str = host_and_port;
+ return true;
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port.data());
+ return false;
+}
+
+IOObject::WaitableHandle Socket::GetWaitableHandle()
+{
+ // TODO: On Windows, use WSAEventSelect
+ return m_socket;
+}
+
+Error Socket::Read (void *buf, size_t &num_bytes)
+{
+ Error error;
+ int bytes_received = 0;
+ do
+ {
+ bytes_received = ::recv (m_socket, static_cast<char *>(buf), num_bytes, 0);
+ // TODO: Use WSAGetLastError on windows.
+ } while (bytes_received < 0 && errno == EINTR);
+
+ if (bytes_received < 0)
+ {
+ error.SetErrorToErrno();
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_received;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_COMMUNICATION));
+ if (log)
+ {
+ log->Printf ("%p Socket::Read() (socket = %" PRIu64 ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)",
+ static_cast<void*>(this),
+ static_cast<uint64_t>(m_socket),
+ buf,
+ static_cast<uint64_t>(num_bytes),
+ static_cast<int64_t>(bytes_received),
+ error.AsCString());
+ }
+
+ return error;
+}
+
+Error Socket::Write (const void *buf, size_t &num_bytes)
+{
+ Error error;
+ int bytes_sent = 0;
+ do
+ {
+ if (m_protocol == ProtocolUdp)
+ {
+ bytes_sent = ::sendto (m_socket,
+ static_cast<const char*>(buf),
+ num_bytes,
+ 0,
+ m_udp_send_sockaddr,
+ m_udp_send_sockaddr.GetLength());
+ }
+ else
+ bytes_sent = ::send (m_socket, static_cast<const char *>(buf), num_bytes, 0);
+ // TODO: Use WSAGetLastError on windows.
+ } while (bytes_sent < 0 && errno == EINTR);
+
+ if (bytes_sent < 0)
+ {
+ // TODO: On Windows, use WSAGEtLastError.
+ error.SetErrorToErrno();
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_sent;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST));
+ if (log)
+ {
+ log->Printf ("%p Socket::Write() (socket = %" PRIu64 ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)",
+ static_cast<void*>(this),
+ static_cast<uint64_t>(m_socket),
+ buf,
+ static_cast<uint64_t>(num_bytes),
+ static_cast<int64_t>(bytes_sent),
+ error.AsCString());
+ }
+
+ return error;
+}
+
+Error Socket::PreDisconnect()
+{
+ Error error;
+ return error;
+}
+
+Error Socket::Close()
+{
+ Error error;
+ if (!IsValid() || !m_should_close_fd)
+ return error;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p Socket::Close (fd = %i)", static_cast<void*>(this), m_socket);
+
+#if defined(_WIN32)
+ bool success = !!closesocket(m_socket);
+#else
+ bool success = !!::close (m_socket);
+#endif
+ // A reference to a FD was passed in, set it to an invalid value
+ m_socket = kInvalidSocketValue;
+ if (!success)
+ {
+ // TODO: On Windows, use WSAGetLastError().
+ error.SetErrorToErrno();
+ }
+
+ return error;
+}
+
+
+int Socket::GetOption(int level, int option_name, int &option_value)
+{
+ get_socket_option_arg_type option_value_p = reinterpret_cast<get_socket_option_arg_type>(&option_value);
+ socklen_t option_value_size = sizeof(int);
+ return ::getsockopt(m_socket, level, option_name, option_value_p, &option_value_size);
+}
+
+int Socket::SetOption(int level, int option_name, int option_value)
+{
+ set_socket_option_arg_type option_value_p = reinterpret_cast<get_socket_option_arg_type>(&option_value);
+ return ::setsockopt(m_socket, level, option_name, option_value_p, sizeof(option_value));
+}
+
+uint16_t Socket::GetPortNumber(const NativeSocket& socket)
+{
+ // We bound to port zero, so we need to figure out which port we actually bound to
+ if (socket >= 0)
+ {
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength ();
+ if (::getsockname (socket, sock_addr, &sock_addr_len) == 0)
+ return sock_addr.GetPort ();
+ }
+ return 0;
+}
+
+// Return the port number that is being used by the socket.
+uint16_t Socket::GetPortNumber() const
+{
+ return GetPortNumber(m_socket);
+}
diff --git a/source/Host/common/SocketAddress.cpp b/source/Host/common/SocketAddress.cpp
index 75f3cd13f586..a952a83185fb 100644
--- a/source/Host/common/SocketAddress.cpp
+++ b/source/Host/common/SocketAddress.cpp
@@ -11,7 +11,7 @@
#include <stddef.h>
// C Includes
-#if !defined(_MSC_VER)
+#if !defined(_WIN32)
#include <arpa/inet.h>
#endif
#include <assert.h>
@@ -90,6 +90,7 @@ GetFamilyLength (sa_family_t family)
case AF_INET6: return sizeof(struct sockaddr_in6);
}
assert(0 && "Unsupported address family");
+ return 0;
}
socklen_t
diff --git a/source/Host/common/SoftwareBreakpoint.cpp b/source/Host/common/SoftwareBreakpoint.cpp
new file mode 100644
index 000000000000..fe2f504ebc71
--- /dev/null
+++ b/source/Host/common/SoftwareBreakpoint.cpp
@@ -0,0 +1,296 @@
+//===-- SoftwareBreakpoint.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SoftwareBreakpoint.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Host/Debug.h"
+#include "lldb/Host/Mutex.h"
+
+#include "NativeProcessProtocol.h"
+
+using namespace lldb_private;
+
+// -------------------------------------------------------------------
+// static members
+// -------------------------------------------------------------------
+
+Error
+SoftwareBreakpoint::CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_sp)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ // Validate the address.
+ if (addr == LLDB_INVALID_ADDRESS)
+ return Error ("SoftwareBreakpoint::%s invalid load address specified.", __FUNCTION__);
+
+ // Ask the NativeProcessProtocol subclass to fill in the correct software breakpoint
+ // trap for the breakpoint site.
+ size_t bp_opcode_size = 0;
+ const uint8_t *bp_opcode_bytes = NULL;
+ Error error = process.GetSoftwareBreakpointTrapOpcode (size_hint, bp_opcode_size, bp_opcode_bytes);
+
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to retrieve software breakpoint trap opcode: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ // Validate size of trap opcode.
+ if (bp_opcode_size == 0)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to retrieve any trap opcodes", __FUNCTION__);
+ return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned zero, unable to get breakpoint trap for address 0x%" PRIx64, addr);
+ }
+
+ if (bp_opcode_size > MAX_TRAP_OPCODE_SIZE)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s cannot support %lu trapcode bytes, max size is %lu", __FUNCTION__, bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
+ return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned too many trap opcode bytes: requires %lu but we only support a max of %lu", bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
+ }
+
+ // Validate that we received opcodes.
+ if (!bp_opcode_bytes)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to retrieve trap opcode bytes", __FUNCTION__);
+ return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned NULL trap opcode bytes, unable to get breakpoint trap for address 0x%" PRIx64, addr);
+ }
+
+ // Enable the breakpoint.
+ uint8_t saved_opcode_bytes [MAX_TRAP_OPCODE_SIZE];
+ error = EnableSoftwareBreakpoint (process, addr, bp_opcode_size, bp_opcode_bytes, saved_opcode_bytes);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s: failed to enable new breakpoint at 0x%" PRIx64 ": %s", __FUNCTION__, addr, error.AsCString ());
+ return error;
+ }
+
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr);
+
+ // Set the breakpoint and verified it was written properly. Now
+ // create a breakpoint remover that understands how to undo this
+ // breakpoint.
+ breakpoint_sp.reset (new SoftwareBreakpoint (process, addr, saved_opcode_bytes, bp_opcode_bytes, bp_opcode_size));
+ return Error ();
+}
+
+Error
+SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes)
+{
+ assert (bp_opcode_size <= MAX_TRAP_OPCODE_SIZE && "bp_opcode_size out of valid range");
+ assert (bp_opcode_bytes && "bp_opcode_bytes is NULL");
+ assert (saved_opcode_bytes && "saved_opcode_bytes is NULL");
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ // Save the original opcodes by reading them so we can restore later.
+ lldb::addr_t bytes_read = 0;
+
+ Error error = process.ReadMemory(addr, saved_opcode_bytes, static_cast<lldb::addr_t> (bp_opcode_size), bytes_read);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ // Ensure we read as many bytes as we expected.
+ if (bytes_read != static_cast<lldb::addr_t> (bp_opcode_size))
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_read);
+ return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_read);
+ }
+
+ // Write a software breakpoint in place of the original opcode.
+ lldb::addr_t bytes_written = 0;
+ error = process.WriteMemory (addr, bp_opcode_bytes, static_cast<lldb::addr_t> (bp_opcode_size), bytes_written);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to write memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ // Ensure we wrote as many bytes as we expected.
+ if (bytes_written != static_cast<lldb::addr_t> (bp_opcode_size))
+ {
+ error.SetErrorStringWithFormat("SoftwareBreakpoint::%s failed write memory while attempting to set breakpoint: attempted to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_written);
+ if (log)
+ log->PutCString (error.AsCString ());
+ return error;
+ }
+
+ uint8_t verify_bp_opcode_bytes [MAX_TRAP_OPCODE_SIZE];
+ lldb::addr_t verify_bytes_read = 0;
+ error = process.ReadMemory(addr, verify_bp_opcode_bytes, static_cast<lldb::addr_t> (bp_opcode_size), verify_bytes_read);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify the breakpoint set: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ // Ensure we read as many verification bytes as we expected.
+ if (verify_bytes_read != static_cast<lldb::addr_t> (bp_opcode_size))
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, verify_bytes_read);
+ return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, verify_bytes_read);
+ }
+
+ if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) != 0)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr);
+ return Error ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr);
+ }
+
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr);
+
+ return Error ();
+}
+
+// -------------------------------------------------------------------
+// instance-level members
+// -------------------------------------------------------------------
+
+SoftwareBreakpoint::SoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, const uint8_t *saved_opcodes, const uint8_t *trap_opcodes, size_t opcode_size) :
+ NativeBreakpoint (addr),
+ m_process (process),
+ m_saved_opcodes (),
+ m_trap_opcodes (),
+ m_opcode_size (opcode_size)
+{
+ assert ( opcode_size > 0 && "setting software breakpoint with no trap opcodes");
+ assert ( opcode_size <= MAX_TRAP_OPCODE_SIZE && "trap opcode size too large");
+
+ ::memcpy (m_saved_opcodes, saved_opcodes, opcode_size);
+ ::memcpy (m_trap_opcodes, trap_opcodes, opcode_size);
+}
+
+Error
+SoftwareBreakpoint::DoEnable ()
+{
+ return EnableSoftwareBreakpoint (m_process, m_addr, m_opcode_size, m_trap_opcodes, m_saved_opcodes);
+}
+
+Error
+SoftwareBreakpoint::DoDisable ()
+{
+ Error error;
+ assert (m_addr && (m_addr != LLDB_INVALID_ADDRESS) && "can't remove a software breakpoint for an invalid address");
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, m_addr);
+
+ assert ( (m_opcode_size > 0) && "cannot restore opcodes when there are no opcodes");
+
+ if (m_opcode_size > 0)
+ {
+ // Clear a software breakoint instruction
+ uint8_t curr_break_op [MAX_TRAP_OPCODE_SIZE];
+ bool break_op_found = false;
+ assert (m_opcode_size <= sizeof (curr_break_op));
+
+ // Read the breakpoint opcode
+ lldb::addr_t bytes_read = 0;
+ error = m_process.ReadMemory (m_addr, curr_break_op, m_opcode_size, bytes_read);
+ if (error.Success () && (bytes_read < static_cast<lldb::addr_t> (m_opcode_size)))
+ {
+ error.SetErrorStringWithFormat ("SoftwareBreakpointr::%s addr=0x%" PRIx64 ": tried to read %lu bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, bytes_read);
+ }
+ if (error.Success ())
+ {
+ bool verify = false;
+ // Make sure we have the a breakpoint opcode exists at this address
+ if (::memcmp (curr_break_op, m_trap_opcodes, m_opcode_size) == 0)
+ {
+ break_op_found = true;
+ // We found a valid breakpoint opcode at this address, now restore
+ // the saved opcode.
+ lldb::addr_t bytes_written = 0;
+ error = m_process.WriteMemory (m_addr, m_saved_opcodes, m_opcode_size, bytes_written);
+ if (error.Success () && (bytes_written < static_cast<lldb::addr_t> (m_opcode_size)))
+ {
+ error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, bytes_written);
+ }
+ if (error.Success ())
+ {
+ verify = true;
+ }
+ }
+ else
+ {
+ error.SetErrorString("Original breakpoint trap is no longer in memory.");
+ // Set verify to true and so we can check if the original opcode has already been restored
+ verify = true;
+ }
+
+ if (verify)
+ {
+ uint8_t verify_opcode [MAX_TRAP_OPCODE_SIZE];
+ assert (m_opcode_size <= sizeof (verify_opcode));
+ // Verify that our original opcode made it back to the inferior
+
+ lldb::addr_t verify_bytes_read = 0;
+ error = m_process.ReadMemory (m_addr, verify_opcode, m_opcode_size, verify_bytes_read);
+ if (error.Success () && (verify_bytes_read < static_cast<lldb::addr_t> (m_opcode_size)))
+ {
+ error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to read %lu verification bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, verify_bytes_read);
+ }
+ if (error.Success ())
+ {
+ // compare the memory we just read with the original opcode
+ if (::memcmp (m_saved_opcodes, verify_opcode, m_opcode_size) == 0)
+ {
+ // SUCCESS
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, m_addr);
+ return error;
+ }
+ else
+ {
+ if (break_op_found)
+ error.SetErrorString("Failed to restore original opcode.");
+ }
+ }
+ else
+ error.SetErrorString("Failed to read memory to verify that breakpoint trap was restored.");
+ }
+ }
+ }
+
+ if (log && error.Fail ())
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- FAILED: %s",
+ __FUNCTION__,
+ m_addr,
+ error.AsCString());
+ return error;
+}
+
+bool
+SoftwareBreakpoint::IsSoftwareBreakpoint () const
+{
+ return true;
+}
+
diff --git a/source/Host/common/SoftwareBreakpoint.h b/source/Host/common/SoftwareBreakpoint.h
new file mode 100644
index 000000000000..1fed19eca612
--- /dev/null
+++ b/source/Host/common/SoftwareBreakpoint.h
@@ -0,0 +1,51 @@
+//===-- SoftwareBreakpoint.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_SoftwareBreakpoint_h_
+#define liblldb_SoftwareBreakpoint_h_
+
+#include "lldb/lldb-private-forward.h"
+#include "NativeBreakpoint.h"
+
+namespace lldb_private
+{
+ class SoftwareBreakpoint : public NativeBreakpoint
+ {
+ public:
+ static Error
+ CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_spn);
+
+ SoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, const uint8_t *saved_opcodes, const uint8_t *trap_opcodes, size_t opcode_size);
+
+ protected:
+ Error
+ DoEnable () override;
+
+ Error
+ DoDisable () override;
+
+ bool
+ IsSoftwareBreakpoint () const override;
+
+ private:
+ /// Max number of bytes that a software trap opcode sequence can occupy.
+ static const size_t MAX_TRAP_OPCODE_SIZE = 8;
+
+ NativeProcessProtocol &m_process;
+ uint8_t m_saved_opcodes [MAX_TRAP_OPCODE_SIZE];
+ uint8_t m_trap_opcodes [MAX_TRAP_OPCODE_SIZE];
+ const size_t m_opcode_size;
+
+ static Error
+ EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes);
+
+ };
+}
+
+#endif // #ifndef liblldb_SoftwareBreakpoint_h_
diff --git a/source/Host/common/Terminal.cpp b/source/Host/common/Terminal.cpp
index f63c468bb92c..ca46eb0f744b 100644
--- a/source/Host/common/Terminal.cpp
+++ b/source/Host/common/Terminal.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/Terminal.h"
+#include "llvm/ADT/STLExtras.h"
#include <fcntl.h>
#include <signal.h>
@@ -250,7 +251,7 @@ TerminalState::TTYStateIsValid() const
bool
TerminalState::ProcessGroupIsValid() const
{
- return m_process_group != -1;
+ return static_cast<int32_t>(m_process_group) != -1;
}
//------------------------------------------------------------------
@@ -274,7 +275,7 @@ TerminalStateSwitcher::~TerminalStateSwitcher ()
uint32_t
TerminalStateSwitcher::GetNumberOfStates() const
{
- return sizeof(m_ttystates)/sizeof(TerminalState);
+ return llvm::array_lengthof(m_ttystates);
}
//------------------------------------------------------------------
diff --git a/source/Host/freebsd/Host.cpp b/source/Host/freebsd/Host.cpp
index c4a6ca37e9c4..dc092e86d78b 100644
--- a/source/Host/freebsd/Host.cpp
+++ b/source/Host/freebsd/Host.cpp
@@ -13,7 +13,6 @@
#include <execinfo.h>
#include <sys/types.h>
#include <sys/user.h>
-#include <sys/utsname.h>
#include <sys/sysctl.h>
#include <sys/proc.h>
@@ -27,6 +26,7 @@
#include "lldb/Core/Error.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/StreamFile.h"
@@ -39,8 +39,9 @@
#include "lldb/Core/DataExtractor.h"
#include "lldb/Utility/CleanUp.h"
-#include "llvm/Support/Host.h"
+#include "Plugins/Process/Utility/FreeBSDSignals.h"
+#include "llvm/Support/Host.h"
extern "C" {
extern char **environ;
@@ -86,7 +87,40 @@ Host::ThreadCreated (const char *thread_name)
std::string
Host::GetThreadName (lldb::pid_t pid, lldb::tid_t tid)
{
+ struct kinfo_proc *kp = nullptr, *nkp;
+ size_t len = 0;
+ int error;
+ int name[4] = {
+ CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, (int)pid
+ };
+
+ while (1) {
+ error = sysctl(name, 4, kp, &len, nullptr, 0);
+ if (kp == nullptr || (error != 0 && errno == ENOMEM)) {
+ // Add extra space in case threads are added before next call.
+ len += sizeof(*kp) + len / 10;
+ nkp = (struct kinfo_proc *)realloc(kp, len);
+ if (nkp == nullptr)
+ {
+ free(kp);
+ return std::string();
+ }
+ kp = nkp;
+ continue;
+ }
+ if (error != 0)
+ len = 0;
+ break;
+ }
+
std::string thread_name;
+ for (size_t i = 0; i < len / sizeof(*kp); i++) {
+ if (kp[i].ki_tid == (int)tid) {
+ thread_name = kp[i].ki_tdname;
+ break;
+ }
+ }
+ free(kp);
return thread_name;
}
@@ -134,56 +168,6 @@ Host::GetEnvironment (StringList &env)
return env.GetSize();
}
-bool
-Host::GetOSVersion(uint32_t &major,
- uint32_t &minor,
- uint32_t &update)
-{
- struct utsname un;
-
- ::memset(&un, 0, sizeof(utsname));
- if (uname(&un) < 0)
- return false;
-
- int status = sscanf(un.release, "%u.%u", &major, &minor);
- return status == 2;
-}
-
-bool
-Host::GetOSBuildString (std::string &s)
-{
- int mib[2] = { CTL_KERN, KERN_OSREV };
- char osrev_str[12];
- uint32_t osrev = 0;
- size_t osrev_len = sizeof(osrev);
-
- if (::sysctl (mib, 2, &osrev, &osrev_len, NULL, 0) == 0)
- {
- ::snprintf(osrev_str, sizeof(osrev_str), "%-8.8u", osrev);
- s.assign (osrev_str);
- return true;
- }
-
- s.clear();
- return false;
-}
-
-bool
-Host::GetOSKernelDescription (std::string &s)
-{
- struct utsname un;
-
- ::memset(&un, 0, sizeof(utsname));
- s.clear();
-
- if (uname(&un) < 0)
- return false;
-
- s.assign (un.version);
-
- return true;
-}
-
static bool
GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
ProcessInstanceInfo &process_info)
@@ -240,7 +224,7 @@ GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info)
{
if (process_info.ProcessIDIsValid())
{
- process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
+ process_info.GetArchitecture() = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
return true;
}
process_info.GetArchitecture().Clear();
@@ -306,9 +290,9 @@ Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstance
const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
bool all_users = match_info.GetMatchAllUsers();
- const lldb::pid_t our_pid = getpid();
+ const ::pid_t our_pid = getpid();
const uid_t our_uid = getuid();
- for (int i = 0; i < actual_pid_count; i++)
+ for (size_t i = 0; i < actual_pid_count; i++)
{
const struct kinfo_proc &kinfo = kinfos[i];
const bool kinfo_user_matches = (all_users ||
@@ -418,3 +402,11 @@ Host::GetAuxvData(lldb_private::Process *process)
done:
return buf_sp;
}
+
+const UnixSignalsSP&
+Host::GetUnixSignals ()
+{
+ static const lldb_private::UnixSignalsSP s_unix_signals_sp (new FreeBSDSignals ());
+ return s_unix_signals_sp;
+}
+
diff --git a/source/Host/freebsd/HostInfoFreeBSD.cpp b/source/Host/freebsd/HostInfoFreeBSD.cpp
new file mode 100644
index 000000000000..78458259f0a2
--- /dev/null
+++ b/source/Host/freebsd/HostInfoFreeBSD.cpp
@@ -0,0 +1,85 @@
+//===-- HostInfoFreeBSD.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/Host/freebsd/HostInfoFreeBSD.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+
+using namespace lldb_private;
+
+bool
+HostInfoFreeBSD::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update)
+{
+ struct utsname un;
+
+ ::memset(&un, 0, sizeof(utsname));
+ if (uname(&un) < 0)
+ return false;
+
+ int status = sscanf(un.release, "%u.%u", &major, &minor);
+ return status == 2;
+}
+
+bool
+HostInfoFreeBSD::GetOSBuildString(std::string &s)
+{
+ int mib[2] = {CTL_KERN, KERN_OSREV};
+ char osrev_str[12];
+ uint32_t osrev = 0;
+ size_t osrev_len = sizeof(osrev);
+
+ if (::sysctl(mib, 2, &osrev, &osrev_len, NULL, 0) == 0)
+ {
+ ::snprintf(osrev_str, sizeof(osrev_str), "%-8.8u", osrev);
+ s.assign(osrev_str);
+ return true;
+ }
+
+ s.clear();
+ return false;
+}
+
+bool
+HostInfoFreeBSD::GetOSKernelDescription(std::string &s)
+{
+ struct utsname un;
+
+ ::memset(&un, 0, sizeof(utsname));
+ s.clear();
+
+ if (uname(&un) < 0)
+ return false;
+
+ s.assign(un.version);
+
+ return true;
+}
+
+FileSpec
+HostInfoFreeBSD::GetProgramFileSpec()
+{
+ static FileSpec g_program_filespec;
+ if (!g_program_filespec)
+ {
+ int exe_path_mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, getpid()};
+ size_t exe_path_size;
+ if (sysctl(exe_path_mib, 4, NULL, &exe_path_size, NULL, 0) == 0)
+ {
+ char *exe_path = new char[exe_path_size];
+ if (sysctl(exe_path_mib, 4, exe_path, &exe_path_size, NULL, 0) == 0)
+ g_program_filespec.SetFile(exe_path, false);
+ delete[] exe_path;
+ }
+ }
+ return g_program_filespec;
+} \ No newline at end of file
diff --git a/source/Host/posix/FileSystem.cpp b/source/Host/posix/FileSystem.cpp
new file mode 100644
index 000000000000..571316811142
--- /dev/null
+++ b/source/Host/posix/FileSystem.cpp
@@ -0,0 +1,201 @@
+//===-- FileSystem.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/Host/FileSystem.h"
+
+// C includes
+#include <sys/stat.h>
+#include <sys/types.h>
+
+// lldb Includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Host.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+FileSpec::PathSyntax
+FileSystem::GetNativePathSyntax()
+{
+ return FileSpec::ePathSyntaxPosix;
+}
+
+Error
+FileSystem::MakeDirectory(const char *path, uint32_t file_permissions)
+{
+ Error error;
+ if (path && path[0])
+ {
+ if (::mkdir(path, file_permissions) != 0)
+ {
+ error.SetErrorToErrno();
+ switch (error.GetError())
+ {
+ case ENOENT:
+ {
+ // Parent directory doesn't exist, so lets make it if we can
+ FileSpec spec(path, false);
+ if (spec.GetDirectory() && spec.GetFilename())
+ {
+ // Make the parent directory and try again
+ Error error2 = MakeDirectory(spec.GetDirectory().GetCString(), file_permissions);
+ if (error2.Success())
+ {
+ // Try and make the directory again now that the parent directory was made successfully
+ if (::mkdir(path, file_permissions) == 0)
+ error.Clear();
+ else
+ error.SetErrorToErrno();
+ }
+ }
+ }
+ break;
+
+ case EEXIST:
+ {
+ FileSpec path_spec(path, false);
+ if (path_spec.IsDirectory())
+ error.Clear(); // It is a directory and it already exists
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("empty path");
+ }
+ return error;
+}
+
+Error
+FileSystem::DeleteDirectory(const char *path, bool recurse)
+{
+ Error error;
+ if (path && path[0])
+ {
+ if (recurse)
+ {
+ StreamString command;
+ command.Printf("rm -rf \"%s\"", path);
+ int status = ::system(command.GetString().c_str());
+ if (status != 0)
+ error.SetError(status, eErrorTypeGeneric);
+ }
+ else
+ {
+ if (::rmdir(path) != 0)
+ error.SetErrorToErrno();
+ }
+ }
+ else
+ {
+ error.SetErrorString("empty path");
+ }
+ return error;
+}
+
+Error
+FileSystem::GetFilePermissions(const char *path, uint32_t &file_permissions)
+{
+ Error error;
+ struct stat file_stats;
+ if (::stat(path, &file_stats) == 0)
+ {
+ // The bits in "st_mode" currently match the definitions
+ // for the file mode bits in unix.
+ file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ }
+ else
+ {
+ error.SetErrorToErrno();
+ }
+ return error;
+}
+
+Error
+FileSystem::SetFilePermissions(const char *path, uint32_t file_permissions)
+{
+ Error error;
+ if (::chmod(path, file_permissions) != 0)
+ error.SetErrorToErrno();
+ return error;
+}
+
+lldb::user_id_t
+FileSystem::GetFileSize(const FileSpec &file_spec)
+{
+ return file_spec.GetByteSize();
+}
+
+bool
+FileSystem::GetFileExists(const FileSpec &file_spec)
+{
+ return file_spec.Exists();
+}
+
+Error
+FileSystem::Symlink(const char *src, const char *dst)
+{
+ Error error;
+ if (::symlink(dst, src) == -1)
+ error.SetErrorToErrno();
+ return error;
+}
+
+Error
+FileSystem::Unlink(const char *path)
+{
+ Error error;
+ if (::unlink(path) == -1)
+ error.SetErrorToErrno();
+ return error;
+}
+
+Error
+FileSystem::Readlink(const char *path, char *buf, size_t buf_len)
+{
+ Error error;
+ ssize_t count = ::readlink(path, buf, buf_len);
+ if (count < 0)
+ error.SetErrorToErrno();
+ else if (static_cast<size_t>(count) < (buf_len - 1))
+ buf[count] = '\0'; // Success
+ else
+ error.SetErrorString("'buf' buffer is too small to contain link contents");
+ return error;
+}
+
+bool
+FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high)
+{
+#if defined(__APPLE__)
+ StreamString md5_cmd_line;
+ md5_cmd_line.Printf("md5 -q '%s'", file_spec.GetPath().c_str());
+ std::string hash_string;
+ Error err = Host::RunShellCommand(md5_cmd_line.GetData(), NULL, NULL, NULL, &hash_string, 60);
+ if (err.Fail())
+ return false;
+ // a correctly formed MD5 is 16-bytes, that is 32 hex digits
+ // if the output is any other length it is probably wrong
+ if (hash_string.size() != 32)
+ return false;
+ std::string part1(hash_string, 0, 16);
+ std::string part2(hash_string, 16);
+ const char *part1_cstr = part1.c_str();
+ const char *part2_cstr = part2.c_str();
+ high = ::strtoull(part1_cstr, NULL, 16);
+ low = ::strtoull(part2_cstr, NULL, 16);
+ return true;
+#else
+ // your own MD5 implementation here
+ return false;
+#endif
+}
diff --git a/source/Host/posix/HostInfoPosix.cpp b/source/Host/posix/HostInfoPosix.cpp
new file mode 100644
index 000000000000..77fdc2b61a31
--- /dev/null
+++ b/source/Host/posix/HostInfoPosix.cpp
@@ -0,0 +1,193 @@
+//===-- HostInfoPosix.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Host/posix/HostInfoPosix.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <grp.h>
+#include <limits.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+using namespace lldb_private;
+
+size_t
+HostInfoPosix::GetPageSize()
+{
+ return ::getpagesize();
+}
+
+bool
+HostInfoPosix::GetHostname(std::string &s)
+{
+ char hostname[PATH_MAX];
+ hostname[sizeof(hostname) - 1] = '\0';
+ if (::gethostname(hostname, sizeof(hostname) - 1) == 0)
+ {
+ struct hostent *h = ::gethostbyname(hostname);
+ if (h)
+ s.assign(h->h_name);
+ else
+ s.assign(hostname);
+ return true;
+ }
+ return false;
+}
+
+const char *
+HostInfoPosix::LookupUserName(uint32_t uid, std::string &user_name)
+{
+ struct passwd user_info;
+ struct passwd *user_info_ptr = &user_info;
+ char user_buffer[PATH_MAX];
+ size_t user_buffer_size = sizeof(user_buffer);
+ if (::getpwuid_r(uid, &user_info, user_buffer, user_buffer_size, &user_info_ptr) == 0)
+ {
+ if (user_info_ptr)
+ {
+ user_name.assign(user_info_ptr->pw_name);
+ return user_name.c_str();
+ }
+ }
+ user_name.clear();
+ return NULL;
+}
+
+const char *
+HostInfoPosix::LookupGroupName(uint32_t gid, std::string &group_name)
+{
+ char group_buffer[PATH_MAX];
+ size_t group_buffer_size = sizeof(group_buffer);
+ struct group group_info;
+ struct group *group_info_ptr = &group_info;
+ // Try the threadsafe version first
+ if (::getgrgid_r(gid, &group_info, group_buffer, group_buffer_size, &group_info_ptr) == 0)
+ {
+ if (group_info_ptr)
+ {
+ group_name.assign(group_info_ptr->gr_name);
+ return group_name.c_str();
+ }
+ }
+ else
+ {
+ // The threadsafe version isn't currently working for me on darwin, but the non-threadsafe version
+ // is, so I am calling it below.
+ group_info_ptr = ::getgrgid(gid);
+ if (group_info_ptr)
+ {
+ group_name.assign(group_info_ptr->gr_name);
+ return group_name.c_str();
+ }
+ }
+ group_name.clear();
+ return NULL;
+}
+
+uint32_t
+HostInfoPosix::GetUserID()
+{
+ return getuid();
+}
+
+uint32_t
+HostInfoPosix::GetGroupID()
+{
+ return getgid();
+}
+
+uint32_t
+HostInfoPosix::GetEffectiveUserID()
+{
+ return geteuid();
+}
+
+uint32_t
+HostInfoPosix::GetEffectiveGroupID()
+{
+ return getegid();
+}
+
+bool
+HostInfoPosix::ComputeSupportExeDirectory(FileSpec &file_spec)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+
+ FileSpec lldb_file_spec;
+ if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ char raw_path[PATH_MAX];
+ lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
+
+ // Most Posix systems (e.g. Linux/*BSD) will attempt to replace a */lib with */bin as the base
+ // directory for helper exe programs. This will fail if the /lib and /bin directories are
+ // rooted in entirely different trees.
+ if (log)
+ log->Printf("HostInfoPosix::ComputeSupportExeDirectory() attempting to derive the bin path (ePathTypeSupportExecutableDir) from "
+ "this path: %s",
+ raw_path);
+ char *lib_pos = ::strstr(raw_path, "/lib");
+ if (lib_pos != nullptr)
+ {
+ // First terminate the raw path at the start of lib.
+ *lib_pos = '\0';
+
+ // Now write in bin in place of lib.
+ ::strncpy(lib_pos, "/bin", PATH_MAX - (lib_pos - raw_path));
+
+ if (log)
+ log->Printf("Host::%s() derived the bin path as: %s", __FUNCTION__, raw_path);
+ }
+ else
+ {
+ if (log)
+ log->Printf("Host::%s() failed to find /lib/liblldb within the shared lib path, bailing on bin path construction",
+ __FUNCTION__);
+ }
+ file_spec.GetDirectory().SetCString(raw_path);
+ return (bool)file_spec.GetDirectory();
+}
+
+bool
+HostInfoPosix::ComputeHeaderDirectory(FileSpec &file_spec)
+{
+ FileSpec temp_file("/opt/local/include/lldb", false);
+ file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str());
+ return true;
+}
+
+bool
+HostInfoPosix::ComputePythonDirectory(FileSpec &file_spec)
+{
+ FileSpec lldb_file_spec;
+ if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ char raw_path[PATH_MAX];
+ lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
+
+ llvm::SmallString<256> python_version_dir;
+ llvm::raw_svector_ostream os(python_version_dir);
+ os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION << "/site-packages";
+ os.flush();
+
+ // We may get our string truncated. Should we protect this with an assert?
+ ::strncat(raw_path, python_version_dir.c_str(), sizeof(raw_path) - strlen(raw_path) - 1);
+
+ file_spec.GetDirectory().SetCString(raw_path);
+ return true;
+}
diff --git a/source/Host/posix/HostProcessPosix.cpp b/source/Host/posix/HostProcessPosix.cpp
new file mode 100644
index 000000000000..4618de4711de
--- /dev/null
+++ b/source/Host/posix/HostProcessPosix.cpp
@@ -0,0 +1,103 @@
+//===-- HostProcessWindows.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/Host/posix/HostProcessPosix.h"
+#include "lldb/Host/FileSystem.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+#include <limits.h>
+
+using namespace lldb_private;
+
+const lldb::pid_t HostProcessPosix::kInvalidProcessId = 0;
+
+HostProcessPosix::HostProcessPosix()
+: m_pid(kInvalidProcessId)
+{
+}
+
+HostProcessPosix::~HostProcessPosix()
+{
+}
+
+Error HostProcessPosix::Create(lldb::pid_t pid)
+{
+ Error error;
+ if (pid == kInvalidProcessId)
+ error.SetErrorString("Attempt to create an invalid process");
+
+ m_pid = pid;
+ return error;
+}
+
+Error HostProcessPosix::Signal(int signo) const
+{
+ if (m_pid <= 0)
+ {
+ Error error;
+ error.SetErrorString("HostProcessPosix refers to an invalid process");
+ return error;
+ }
+
+ return HostProcessPosix::Signal(m_pid, signo);
+}
+
+Error HostProcessPosix::Signal(lldb::pid_t pid, int signo)
+{
+ Error error;
+
+ if (-1 == ::kill(pid, signo))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error HostProcessPosix::GetMainModule(FileSpec &file_spec) const
+{
+ Error error;
+
+ // Use special code here because proc/[pid]/exe is a symbolic link.
+ char link_path[PATH_MAX];
+ char exe_path[PATH_MAX] = "";
+ if (snprintf (link_path, PATH_MAX, "/proc/%" PRIu64 "/exe", m_pid) <= 0)
+ {
+ error.SetErrorString("Unable to build /proc/<pid>/exe string");
+ return error;
+ }
+
+ error = FileSystem::Readlink(link_path, exe_path, llvm::array_lengthof(exe_path));
+ if (!error.Success())
+ return error;
+
+ const ssize_t len = strlen(exe_path);
+ // If the binary has been deleted, the link name has " (deleted)" appended.
+ // Remove if there.
+ static const ssize_t deleted_len = strlen(" (deleted)");
+ if (len > deleted_len &&
+ !strcmp(exe_path + len - deleted_len, " (deleted)"))
+ {
+ exe_path[len - deleted_len] = 0;
+ }
+
+ file_spec.SetFile(exe_path, false);
+ return error;
+}
+
+lldb::pid_t HostProcessPosix::GetProcessId() const
+{
+ return m_pid;
+}
+
+bool HostProcessPosix::IsRunning() const
+{
+ // Send this process the null signal. If it succeeds the process is running.
+ Error error = Signal(0);
+ return error.Success();
+}
diff --git a/source/Interpreter/Args.cpp b/source/Interpreter/Args.cpp
index b6f34fd1f7fb..4831eaaac348 100644
--- a/source/Interpreter/Args.cpp
+++ b/source/Interpreter/Args.cpp
@@ -20,6 +20,7 @@
#include "lldb/Core/StreamString.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Target/Process.h"
//#include "lldb/Target/RegisterContext.h"
@@ -166,7 +167,7 @@ Args::SetCommandString (const char *command)
{
static const char *k_space_separators = " \t";
static const char *k_space_separators_with_slash_and_quotes = " \t \\'\"";
- const char *arg_end = NULL;
+ const char *arg_end = nullptr;
const char *arg_pos;
for (arg_pos = command;
arg_pos && arg_pos[0];
@@ -371,7 +372,7 @@ Args::UpdateArgsAfterOptionParsing()
++argv_pos)
{
const char *argv_cstr = *argv_pos;
- if (argv_cstr == NULL)
+ if (argv_cstr == nullptr)
break;
while (args_pos != m_args.end())
@@ -407,7 +408,7 @@ Args::UpdateArgvFromArgs()
arg_sstr_collection::const_iterator pos, end = m_args.end();
for (pos = m_args.begin(); pos != end; ++pos)
m_argv.push_back(pos->c_str());
- m_argv.push_back(NULL);
+ m_argv.push_back(nullptr);
// Make sure we have enough arg quote chars in the array
if (m_args_quote_char.size() < m_args.size())
m_args_quote_char.resize (m_argv.size());
@@ -426,7 +427,7 @@ Args::GetArgumentAtIndex (size_t idx) const
{
if (idx < m_argv.size())
return m_argv[idx];
- return NULL;
+ return nullptr;
}
char
@@ -442,7 +443,7 @@ Args::GetArgumentVector()
{
if (!m_argv.empty())
return (char **)&m_argv[0];
- return NULL;
+ return nullptr;
}
const char **
@@ -450,7 +451,7 @@ Args::GetConstArgumentVector() const
{
if (!m_argv.empty())
return (const char **)&m_argv[0];
- return NULL;
+ return nullptr;
}
void
@@ -545,7 +546,7 @@ Args::ReplaceArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char)
m_args_quote_char[idx] = quote_char;
return GetArgumentAtIndex(idx);
}
- return NULL;
+ return nullptr;
}
void
@@ -621,20 +622,20 @@ Args::ParseOptions (Options &options)
StreamString sstr;
Error error;
Option *long_options = options.GetLongOptions();
- if (long_options == NULL)
+ if (long_options == nullptr)
{
error.SetErrorStringWithFormat("invalid long options");
return error;
}
- for (int i=0; long_options[i].name != NULL; ++i)
+ for (int i=0; long_options[i].definition != nullptr; ++i)
{
- if (long_options[i].flag == NULL)
+ if (long_options[i].flag == nullptr)
{
if (isprint8(long_options[i].val))
{
sstr << (char)long_options[i].val;
- switch (long_options[i].has_arg)
+ switch (long_options[i].definition->option_has_arg)
{
default:
case OptionParser::eNoArgument: break;
@@ -673,7 +674,7 @@ Args::ParseOptions (Options &options)
if (long_options_index == -1)
{
for (int i=0;
- long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val;
+ long_options[i].definition || long_options[i].flag || long_options[i].val;
++i)
{
if (long_options[i].val == val)
@@ -686,8 +687,18 @@ Args::ParseOptions (Options &options)
// Call the callback with the option
if (long_options_index >= 0)
{
- error = options.SetOptionValue(long_options_index,
- long_options[long_options_index].has_arg == OptionParser::eNoArgument ? NULL : OptionParser::GetOptionArgument());
+ const OptionDefinition *def = long_options[long_options_index].definition;
+ CommandInterpreter &interpreter = options.GetInterpreter();
+ OptionValidator *validator = def->validator;
+ if (validator && !validator->IsValid(*interpreter.GetPlatform(true), interpreter.GetExecutionContext()))
+ {
+ error.SetErrorStringWithFormat("Option \"%s\" invalid. %s", def->long_option, def->validator->LongConditionString());
+ }
+ else
+ {
+ error = options.SetOptionValue(long_options_index,
+ (def->option_has_arg == OptionParser::eNoArgument) ? nullptr : OptionParser::GetOptionArgument());
+ }
}
else
{
@@ -716,7 +727,7 @@ Args::StringToSInt32 (const char *s, int32_t fail_value, int base, bool *success
{
if (s && s[0])
{
- char *end = NULL;
+ char *end = nullptr;
const long sval = ::strtol (s, &end, base);
if (*end == '\0')
{
@@ -734,7 +745,7 @@ Args::StringToUInt32 (const char *s, uint32_t fail_value, int base, bool *succes
{
if (s && s[0])
{
- char *end = NULL;
+ char *end = nullptr;
const unsigned long uval = ::strtoul (s, &end, base);
if (*end == '\0')
{
@@ -753,7 +764,7 @@ Args::StringToSInt64 (const char *s, int64_t fail_value, int base, bool *success
{
if (s && s[0])
{
- char *end = NULL;
+ char *end = nullptr;
int64_t uval = ::strtoll (s, &end, base);
if (*end == '\0')
{
@@ -770,7 +781,7 @@ Args::StringToUInt64 (const char *s, uint64_t fail_value, int base, bool *succes
{
if (s && s[0])
{
- char *end = NULL;
+ char *end = nullptr;
uint64_t uval = ::strtoull (s, &end, base);
if (*end == '\0')
{
@@ -788,7 +799,7 @@ Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::add
bool error_set = false;
if (s && s[0])
{
- char *end = NULL;
+ char *end = nullptr;
lldb::addr_t addr = ::strtoull (s, &end, 0);
if (*end == '\0')
{
@@ -817,13 +828,13 @@ Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::add
options.SetKeepInMemory(false);
options.SetTryAllThreads(true);
- ExecutionResults expr_result = target->EvaluateExpression(s,
+ ExpressionResults expr_result = target->EvaluateExpression(s,
exe_ctx->GetFramePtr(),
valobj_sp,
options);
bool success = false;
- if (expr_result == eExecutionCompleted)
+ if (expr_result == eExpressionCompleted)
{
// Get the address to watch.
addr = valobj_sp->GetValueAsUnsigned(fail_value, &success);
@@ -923,7 +934,7 @@ Args::StripSpaces (std::string &s, bool leading, bool trailing, bool return_null
}
}
if (return_null_if_empty && s.empty())
- return NULL;
+ return nullptr;
return s.c_str();
}
@@ -964,7 +975,7 @@ Args::StringToVersion (const char *s, uint32_t &major, uint32_t &minor, uint32_t
if (s && s[0])
{
- char *pos = NULL;
+ char *pos = nullptr;
unsigned long uval32 = ::strtoul (s, &pos, 0);
if (pos == s)
return s;
@@ -991,7 +1002,7 @@ Args::StringToVersion (const char *s, uint32_t &major, uint32_t &minor, uint32_t
return pos;
}
}
- return 0;
+ return nullptr;
}
const char *
@@ -1022,7 +1033,7 @@ Args::StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, in
{
if (s && s[0])
{
- for (int i = 0; enum_values[i].string_value != NULL ; i++)
+ for (int i = 0; enum_values[i].string_value != nullptr ; i++)
{
if (strstr(enum_values[i].string_value, s) == enum_values[i].string_value)
{
@@ -1034,7 +1045,7 @@ Args::StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, in
StreamString strm;
strm.PutCString ("invalid enumeration value, valid values are: ");
- for (int i = 0; enum_values[i].string_value != NULL; i++)
+ for (int i = 0; enum_values[i].string_value != nullptr; i++)
{
strm.Printf ("%s\"%s\"",
i > 0 ? ", " : "",
@@ -1087,7 +1098,7 @@ Args::StringToFormat
{
if (isdigit (s[0]))
{
- char *format_char = NULL;
+ char *format_char = nullptr;
unsigned long byte_size = ::strtoul (s, &format_char, 0);
if (byte_size != ULONG_MAX)
*byte_size_ptr = byte_size;
@@ -1155,7 +1166,7 @@ Args::StringToGenericRegister (const char *s)
return LLDB_REGNUM_GENERIC_SP;
else if (strcmp(s, "fp") == 0)
return LLDB_REGNUM_GENERIC_FP;
- else if (strcmp(s, "ra") == 0)
+ else if (strcmp(s, "ra") == 0 || strcmp(s, "lr") == 0)
return LLDB_REGNUM_GENERIC_RA;
else if (strcmp(s, "flags") == 0)
return LLDB_REGNUM_GENERIC_FLAGS;
@@ -1222,7 +1233,7 @@ Args::FindArgumentIndexForOption (Option *long_options, int long_options_index)
char short_buffer[3];
char long_buffer[255];
::snprintf (short_buffer, sizeof (short_buffer), "-%c", long_options[long_options_index].val);
- ::snprintf (long_buffer, sizeof (long_buffer), "--%s", long_options[long_options_index].name);
+ ::snprintf (long_buffer, sizeof (long_buffer), "--%s", long_options[long_options_index].definition->long_option);
size_t end = GetArgumentCount ();
size_t idx = 0;
while (idx < end)
@@ -1241,7 +1252,7 @@ Args::FindArgumentIndexForOption (Option *long_options, int long_options_index)
bool
Args::IsPositionalArgument (const char *arg)
{
- if (arg == NULL)
+ if (arg == nullptr)
return false;
bool is_positional = true;
@@ -1271,19 +1282,19 @@ Args::ParseAliasOptions (Options &options,
int i;
Option *long_options = options.GetLongOptions();
- if (long_options == NULL)
+ if (long_options == nullptr)
{
result.AppendError ("invalid long options");
result.SetStatus (eReturnStatusFailed);
return;
}
- for (i = 0; long_options[i].name != NULL; ++i)
+ for (i = 0; long_options[i].definition != nullptr; ++i)
{
- if (long_options[i].flag == NULL)
+ if (long_options[i].flag == nullptr)
{
sstr << (char) long_options[i].val;
- switch (long_options[i].has_arg)
+ switch (long_options[i].definition->option_has_arg)
{
default:
case OptionParser::eNoArgument:
@@ -1322,13 +1333,13 @@ Args::ParseAliasOptions (Options &options,
if (val == 0)
continue;
- ((Options *) &options)->OptionSeen (val);
+ options.OptionSeen (val);
// Look up the long option index
if (long_options_index == -1)
{
for (int j = 0;
- long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val;
+ long_options[j].definition || long_options[j].flag || long_options[j].val;
++j)
{
if (long_options[j].val == val)
@@ -1344,8 +1355,10 @@ Args::ParseAliasOptions (Options &options,
{
StreamString option_str;
option_str.Printf ("-%c", val);
+ const OptionDefinition *def = long_options[long_options_index].definition;
+ int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
- switch (long_options[long_options_index].has_arg)
+ switch (has_arg)
{
case OptionParser::eNoArgument:
option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
@@ -1353,7 +1366,7 @@ Args::ParseAliasOptions (Options &options,
result.SetStatus (eReturnStatusSuccessFinishNoResult);
break;
case OptionParser::eRequiredArgument:
- if (OptionParser::GetOptionArgument() != NULL)
+ if (OptionParser::GetOptionArgument() != nullptr)
{
option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
OptionArgValue (OptionParser::eRequiredArgument,
@@ -1368,7 +1381,7 @@ Args::ParseAliasOptions (Options &options,
}
break;
case OptionParser::eOptionalArgument:
- if (OptionParser::GetOptionArgument() != NULL)
+ if (OptionParser::GetOptionArgument() != nullptr)
{
option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
OptionArgValue (OptionParser::eOptionalArgument,
@@ -1410,8 +1423,8 @@ Args::ParseAliasOptions (Options &options,
raw_input_string.erase (pos, strlen (tmp_arg));
}
ReplaceArgumentAtIndex (idx, "");
- if ((long_options[long_options_index].has_arg != OptionParser::eNoArgument)
- && (OptionParser::GetOptionArgument() != NULL)
+ if ((long_options[long_options_index].definition->option_has_arg != OptionParser::eNoArgument)
+ && (OptionParser::GetOptionArgument() != nullptr)
&& (idx+1 < GetArgumentCount())
&& (strcmp (OptionParser::GetOptionArgument(), GetArgumentAtIndex(idx+1)) == 0))
{
@@ -1444,7 +1457,7 @@ Args::ParseArgsForCompletion
Option *long_options = options.GetLongOptions();
option_element_vector.clear();
- if (long_options == NULL)
+ if (long_options == nullptr)
{
return;
}
@@ -1453,12 +1466,12 @@ Args::ParseArgsForCompletion
// to suppress error messages.
sstr << ":";
- for (int i = 0; long_options[i].name != NULL; ++i)
+ for (int i = 0; long_options[i].definition != nullptr; ++i)
{
- if (long_options[i].flag == NULL)
+ if (long_options[i].flag == nullptr)
{
sstr << (char) long_options[i].val;
- switch (long_options[i].has_arg)
+ switch (long_options[i].definition->option_has_arg)
{
default:
case OptionParser::eNoArgument:
@@ -1516,11 +1529,11 @@ Args::ParseArgsForCompletion
// were passed. This will be useful when we come to restricting completions based on what other
// options we've seen on the line.
- if (OptionParser::GetOptionIndex() < dummy_vec.size() - 1
+ if (static_cast<size_t>(OptionParser::GetOptionIndex()) < dummy_vec.size() - 1
&& (strcmp (dummy_vec[OptionParser::GetOptionIndex()-1], "--") == 0))
{
dash_dash_pos = OptionParser::GetOptionIndex() - 1;
- if (OptionParser::GetOptionIndex() - 1 == cursor_index)
+ if (static_cast<size_t>(OptionParser::GetOptionIndex() - 1) == cursor_index)
{
option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDoubleDash, OptionParser::GetOptionIndex() - 1,
OptionArgElement::eBareDoubleDash));
@@ -1555,7 +1568,7 @@ Args::ParseArgsForCompletion
if (long_options_index == -1)
{
for (int j = 0;
- long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val;
+ long_options[j].definition || long_options[j].flag || long_options[j].val;
++j)
{
if (long_options[j].val == val)
@@ -1581,13 +1594,15 @@ Args::ParseArgsForCompletion
}
}
- switch (long_options[long_options_index].has_arg)
+ const OptionDefinition *def = long_options[long_options_index].definition;
+ int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
+ switch (has_arg)
{
case OptionParser::eNoArgument:
option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 1, 0));
break;
case OptionParser::eRequiredArgument:
- if (OptionParser::GetOptionArgument() != NULL)
+ if (OptionParser::GetOptionArgument() != nullptr)
{
int arg_index;
if (missing_argument)
@@ -1603,7 +1618,7 @@ Args::ParseArgsForCompletion
}
break;
case OptionParser::eOptionalArgument:
- if (OptionParser::GetOptionArgument() != NULL)
+ if (OptionParser::GetOptionArgument() != nullptr)
{
option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 2, OptionParser::GetOptionIndex() - 1));
}
@@ -1629,8 +1644,10 @@ Args::ParseArgsForCompletion
// Finally we have to handle the case where the cursor index points at a single "-". We want to mark that in
// the option_element_vector, but only if it is not after the "--". But it turns out that OptionParser::Parse just ignores
// an isolated "-". So we have to look it up by hand here. We only care if it is AT the cursor position.
+ // Note, a single quoted dash is not the same as a single dash...
- if ((dash_dash_pos == -1 || cursor_index < dash_dash_pos)
+ if ((static_cast<int32_t>(dash_dash_pos) == -1 || cursor_index < dash_dash_pos)
+ && m_args_quote_char[cursor_index] == '\0'
&& strcmp (GetArgumentAtIndex(cursor_index), "-") == 0)
{
option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDash, cursor_index,
@@ -1686,7 +1703,7 @@ Args::EncodeEscapeSequences (const char *src, std::string &dst)
// the main for loop will do this for us, so we advance p by
// one less than i (even if i is zero)
p += i - 1;
- unsigned long octal_value = ::strtoul (oct_str, NULL, 8);
+ unsigned long octal_value = ::strtoul (oct_str, nullptr, 8);
if (octal_value <= UINT8_MAX)
{
dst.append(1, (char)octal_value);
@@ -1709,7 +1726,7 @@ Args::EncodeEscapeSequences (const char *src, std::string &dst)
hex_str[1] = *p;
}
- unsigned long hex_value = strtoul (hex_str, NULL, 16);
+ unsigned long hex_value = strtoul (hex_str, nullptr, 16);
if (hex_value <= UINT8_MAX)
dst.append (1, (char)hex_value);
}
diff --git a/source/Interpreter/CommandHistory.cpp b/source/Interpreter/CommandHistory.cpp
index 33971e3959c6..26996a625642 100644
--- a/source/Interpreter/CommandHistory.cpp
+++ b/source/Interpreter/CommandHistory.cpp
@@ -41,17 +41,17 @@ CommandHistory::FindString (const char* input_str) const
{
Mutex::Locker locker(m_mutex);
if (!input_str)
- return NULL;
+ return nullptr;
if (input_str[0] != g_repeat_char)
- return NULL;
+ return nullptr;
if (input_str[1] == '-')
{
bool success;
size_t idx = Args::StringToUInt32 (input_str+2, 0, 0, &success);
if (!success)
- return NULL;
+ return nullptr;
if (idx > m_history.size())
- return NULL;
+ return nullptr;
idx = m_history.size() - idx;
return m_history[idx].c_str();
@@ -59,7 +59,7 @@ CommandHistory::FindString (const char* input_str) const
else if (input_str[1] == g_repeat_char)
{
if (m_history.empty())
- return NULL;
+ return nullptr;
else
return m_history.back().c_str();
}
@@ -68,9 +68,9 @@ CommandHistory::FindString (const char* input_str) const
bool success;
uint32_t idx = Args::StringToUInt32 (input_str+1, 0, 0, &success);
if (!success)
- return NULL;
+ return nullptr;
if (idx >= m_history.size())
- return NULL;
+ return nullptr;
return m_history[idx].c_str();
}
}
@@ -81,7 +81,7 @@ CommandHistory::GetStringAtIndex (size_t idx) const
Mutex::Locker locker(m_mutex);
if (idx < m_history.size())
return m_history[idx].c_str();
- return NULL;
+ return nullptr;
}
const char*
@@ -95,7 +95,7 @@ CommandHistory::GetRecentmostString () const
{
Mutex::Locker locker(m_mutex);
if (m_history.empty())
- return NULL;
+ return nullptr;
return m_history.back().c_str();
}
@@ -137,7 +137,7 @@ CommandHistory::Dump (Stream& stream,
if (!hist_item.empty())
{
stream.Indent();
- stream.Printf ("%4zu: %s\n", counter, hist_item.c_str());
+ stream.Printf("%4" PRIu64 ": %s\n", (uint64_t)counter, hist_item.c_str());
}
}
}
diff --git a/source/Interpreter/CommandInterpreter.cpp b/source/Interpreter/CommandInterpreter.cpp
index fb0fc7f700a5..56c8f8c0ad6a 100644
--- a/source/Interpreter/CommandInterpreter.cpp
+++ b/source/Interpreter/CommandInterpreter.cpp
@@ -44,12 +44,14 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/Timer.h"
#include "lldb/Host/Editline.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandCompletions.h"
@@ -66,6 +68,10 @@
#include "lldb/Utility/CleanUp.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Path.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -73,10 +79,10 @@ using namespace lldb_private;
static PropertyDefinition
g_properties[] =
{
- { "expand-regex-aliases", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, regular expression alias commands will show the expanded command that will be executed. This can be used to debug new regular expression alias commands." },
- { "prompt-on-quit", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will prompt you before quitting if there are any live processes being debugged. If false, LLDB will quit without asking in any case." },
- { "stop-command-source-on-error", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will stop running a 'command source' script upon encountering an error." },
- { NULL , OptionValue::eTypeInvalid, true, 0 , NULL, NULL, NULL }
+ { "expand-regex-aliases", OptionValue::eTypeBoolean, true, false, nullptr, nullptr, "If true, regular expression alias commands will show the expanded command that will be executed. This can be used to debug new regular expression alias commands." },
+ { "prompt-on-quit", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, "If true, LLDB will prompt you before quitting if there are any live processes being debugged. If false, LLDB will quit without asking in any case." },
+ { "stop-command-source-on-error", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, "If true, LLDB will stop running a 'command source' script upon encountering an error." },
+ { nullptr , OptionValue::eTypeInvalid, true, 0 , nullptr, nullptr, nullptr }
};
enum
@@ -125,21 +131,21 @@ bool
CommandInterpreter::GetExpandRegexAliases () const
{
const uint32_t idx = ePropertyExpandRegexAliases;
- return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0);
}
bool
CommandInterpreter::GetPromptOnQuit () const
{
const uint32_t idx = ePropertyPromptOnQuit;
- return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0);
}
bool
CommandInterpreter::GetStopCmdSourceOnError () const
{
const uint32_t idx = ePropertyStopCmdSourceOnError;
- return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0);
}
void
@@ -324,7 +330,7 @@ CommandInterpreter::Initialize ()
if (cmd_obj_sp)
{
alias_arguments_vector_sp.reset (new OptionArgVector);
-#if defined (__arm__)
+#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
ProcessAliasOptionsArgs (cmd_obj_sp, "--", alias_arguments_vector_sp);
#else
ProcessAliasOptionsArgs (cmd_obj_sp, "--shell=" LLDB_DEFAULT_SHELL " --", alias_arguments_vector_sp);
@@ -351,6 +357,15 @@ CommandInterpreter::Initialize ()
}
}
+void
+CommandInterpreter::Clear()
+{
+ m_command_io_handler_sp.reset();
+
+ if (m_script_interpreter_ap)
+ m_script_interpreter_ap->Clear();
+}
+
const char *
CommandInterpreter::ProcessEmbeddedScriptCommands (const char *arg)
{
@@ -405,9 +420,9 @@ CommandInterpreter::LoadCommandDictionary ()
{"^(-.*)$", "breakpoint set %1"},
{"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%2' --shlib '%1'"},
{"^\\&(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%1' --skip-prologue=0"},
- {"^(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%1'"}};
+ {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$", "breakpoint set --name '%1'"}};
- size_t num_regexes = sizeof break_regexes/sizeof(char *[2]);
+ size_t num_regexes = llvm::array_lengthof(break_regexes);
std::unique_ptr<CommandObjectRegexCommand>
break_regex_cmd_ap(new CommandObjectRegexCommand (*this,
@@ -702,7 +717,7 @@ CommandInterpreter::GetCommandSP (const char *cmd_cstr, bool include_aliases, bo
CommandObjectSP user_match_sp, alias_match_sp, real_match_sp;
StringList local_matches;
- if (matches == NULL)
+ if (matches == nullptr)
matches = &local_matches;
unsigned int num_cmd_matches = 0;
@@ -830,17 +845,17 @@ CommandInterpreter::GetCommandSPExact (const char *cmd_cstr, bool include_aliase
Args cmd_words (cmd_cstr); // Break up the command string into words, in case it's a multi-word command.
CommandObjectSP ret_val; // Possibly empty return value.
- if (cmd_cstr == NULL)
+ if (cmd_cstr == nullptr)
return ret_val;
if (cmd_words.GetArgumentCount() == 1)
- return GetCommandSP(cmd_cstr, include_aliases, true, NULL);
+ return GetCommandSP(cmd_cstr, include_aliases, true, nullptr);
else
{
// We have a multi-word command (seemingly), so we need to do more work.
// First, get the cmd_obj_sp for the first word in the command.
- CommandObjectSP cmd_obj_sp = GetCommandSP (cmd_words.GetArgumentAtIndex (0), include_aliases, true, NULL);
- if (cmd_obj_sp.get() != NULL)
+ CommandObjectSP cmd_obj_sp = GetCommandSP (cmd_words.GetArgumentAtIndex (0), include_aliases, true, nullptr);
+ if (cmd_obj_sp.get() != nullptr)
{
// Loop through the rest of the words in the command (everything passed in was supposed to be part of a
// command name), and find the appropriate sub-command SP for each command word....
@@ -850,7 +865,7 @@ CommandInterpreter::GetCommandSPExact (const char *cmd_cstr, bool include_aliase
if (cmd_obj_sp->IsMultiwordObject())
{
cmd_obj_sp = cmd_obj_sp->GetSubcommandSP (cmd_words.GetArgumentAtIndex (j));
- if (cmd_obj_sp.get() == NULL)
+ if (cmd_obj_sp.get() == nullptr)
// The sub-command name was invalid. Fail and return the empty 'ret_val'.
return ret_val;
}
@@ -890,7 +905,7 @@ CommandInterpreter::GetCommandObject (const char *cmd_cstr, StringList *matches)
return command_obj;
// If there wasn't an exact match then look for an inexact one in just the commands
- command_obj = GetCommandSP(cmd_cstr, false, false, NULL).get();
+ command_obj = GetCommandSP(cmd_cstr, false, false, nullptr).get();
// Finally, if there wasn't an inexact match among the commands, look for an inexact
// match in both the commands and aliases.
@@ -1156,7 +1171,7 @@ CommandInterpreter::GetCommandObjectForCommand (std::string &command_string)
// This function finds the final, lowest-level, alias-resolved command object whose 'Execute' function will
// eventually be invoked by the given command line.
- CommandObject *cmd_obj = NULL;
+ CommandObject *cmd_obj = nullptr;
std::string white_space (" \t\v");
size_t start = command_string.find_first_not_of (white_space);
size_t end = 0;
@@ -1171,7 +1186,7 @@ CommandInterpreter::GetCommandObjectForCommand (std::string &command_string)
end = command_string.size();
std::string cmd_word = command_string.substr (start, end - start);
- if (cmd_obj == NULL)
+ if (cmd_obj == nullptr)
// Since cmd_obj is NULL we are on our first time through this loop. Check to see if cmd_word is a valid
// command or alias.
cmd_obj = GetCommandObject (cmd_word.c_str());
@@ -1325,7 +1340,7 @@ CommandInterpreter::BuildAliasResult (const char *alias_name,
std::string &alias_result,
CommandReturnObject &result)
{
- CommandObject *alias_cmd_obj = NULL;
+ CommandObject *alias_cmd_obj = nullptr;
Args cmd_args (raw_input_string.c_str());
alias_cmd_obj = GetCommandObject (alias_name);
StreamString result_str;
@@ -1363,7 +1378,7 @@ CommandInterpreter::BuildAliasResult (const char *alias_name,
int index = GetOptionArgumentPosition (value.c_str());
if (index == 0)
result_str.Printf ("%s", value.c_str());
- else if (index >= cmd_args.GetArgumentCount())
+ else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount())
{
result.AppendErrorWithFormat
@@ -1446,12 +1461,12 @@ CommandInterpreter::PreprocessCommand (std::string &command)
options.SetTryAllThreads(true);
options.SetTimeoutUsec(0);
- ExecutionResults expr_result = target->EvaluateExpression (expr_str.c_str(),
+ ExpressionResults expr_result = target->EvaluateExpression (expr_str.c_str(),
exe_ctx.GetFramePtr(),
expr_result_valobj_sp,
options);
- if (expr_result == eExecutionCompleted)
+ if (expr_result == eExpressionCompleted)
{
Scalar scalar;
if (expr_result_valobj_sp->ResolveValue (scalar))
@@ -1486,24 +1501,29 @@ CommandInterpreter::PreprocessCommand (std::string &command)
switch (expr_result)
{
- case eExecutionSetupError:
+ case eExpressionSetupError:
error.SetErrorStringWithFormat("expression setup error for the expression '%s'", expr_str.c_str());
break;
- case eExecutionCompleted:
+ case eExpressionParseError:
+ error.SetErrorStringWithFormat ("expression parse error for the expression '%s'", expr_str.c_str());
+ break;
+ case eExpressionResultUnavailable:
+ error.SetErrorStringWithFormat ("expression error fetching result for the expression '%s'", expr_str.c_str());
+ case eExpressionCompleted:
break;
- case eExecutionDiscarded:
+ case eExpressionDiscarded:
error.SetErrorStringWithFormat("expression discarded for the expression '%s'", expr_str.c_str());
break;
- case eExecutionInterrupted:
+ case eExpressionInterrupted:
error.SetErrorStringWithFormat("expression interrupted for the expression '%s'", expr_str.c_str());
break;
- case eExecutionHitBreakpoint:
+ case eExpressionHitBreakpoint:
error.SetErrorStringWithFormat("expression hit breakpoint for the expression '%s'", expr_str.c_str());
break;
- case eExecutionTimedOut:
+ case eExpressionTimedOut:
error.SetErrorStringWithFormat("expression timed out for the expression '%s'", expr_str.c_str());
break;
- case eExecutionStoppedForDebug:
+ case eExpressionStoppedForDebug:
error.SetErrorStringWithFormat("expression stop at entry point for debugging for the expression '%s'", expr_str.c_str());
break;
}
@@ -1530,7 +1550,7 @@ CommandInterpreter::HandleCommand (const char *command_line,
{
bool done = false;
- CommandObject *cmd_obj = NULL;
+ CommandObject *cmd_obj = nullptr;
bool wants_raw_input = false;
std::string command_string (command_line);
std::string original_command_string (command_line);
@@ -1540,7 +1560,7 @@ CommandInterpreter::HandleCommand (const char *command_line,
// Make a scoped cleanup object that will clear the crash description string
// on exit of this function.
- lldb_utility::CleanUp <const char *> crash_description_cleanup(NULL, Host::SetCrashDescription);
+ lldb_utility::CleanUp <const char *> crash_description_cleanup(nullptr, Host::SetCrashDescription);
if (log)
log->Printf ("Processing command: %s", command_line);
@@ -1574,7 +1594,7 @@ CommandInterpreter::HandleCommand (const char *command_line,
else if (command_string[non_space] == CommandHistory::g_repeat_char)
{
const char *history_string = m_command_history.FindString(command_string.c_str() + non_space);
- if (history_string == NULL)
+ if (history_string == nullptr)
{
result.AppendErrorWithFormat ("Could not find entry: %s in history", command_string.c_str());
result.SetStatus(eReturnStatusFailed);
@@ -1650,7 +1670,7 @@ CommandInterpreter::HandleCommand (const char *command_line,
char quote_char = '\0';
std::string suffix;
ExtractCommand (command_string, next_word, suffix, quote_char);
- if (cmd_obj == NULL)
+ if (cmd_obj == nullptr)
{
std::string full_name;
if (GetAliasFullName(next_word.c_str(), full_name))
@@ -1710,7 +1730,7 @@ CommandInterpreter::HandleCommand (const char *command_line,
}
}
- if (cmd_obj == NULL)
+ if (cmd_obj == nullptr)
{
const size_t num_matches = matches.GetSize();
if (matches.GetSize() > 1) {
@@ -1823,13 +1843,13 @@ CommandInterpreter::HandleCommand (const char *command_line,
// Take care of things like setting up the history command & calling the appropriate Execute method on the
// CommandObject, with the appropriate arguments.
- if (cmd_obj != NULL)
+ if (cmd_obj != nullptr)
{
if (add_to_history)
{
Args command_args (revised_command_line.GetData());
const char *repeat_command = cmd_obj->GetRepeatCommand(command_args, 0);
- if (repeat_command != NULL)
+ if (repeat_command != nullptr)
m_repeat_command.assign(repeat_command);
else
m_repeat_command.assign(original_command_string.c_str());
@@ -1931,7 +1951,7 @@ CommandInterpreter::HandleCompletionMatches (Args &parsed_line,
if (num_command_matches == 1
&& cmd_obj && cmd_obj->IsMultiwordObject()
- && matches.GetStringAtIndex(0) != NULL
+ && matches.GetStringAtIndex(0) != nullptr
&& strcmp (parsed_line.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0)
{
if (parsed_line.GetArgumentCount() == 1)
@@ -1956,7 +1976,7 @@ CommandInterpreter::HandleCompletionMatches (Args &parsed_line,
// to complete the command.
// First see if there is a matching initial command:
CommandObject *command_object = GetCommandObject (parsed_line.GetArgumentAtIndex(0));
- if (command_object == NULL)
+ if (command_object == nullptr)
{
return 0;
}
@@ -2002,7 +2022,7 @@ CommandInterpreter::HandleCompletion (const char *current_line,
else if (first_arg[0] == CommandHistory::g_repeat_char)
{
const char *history_string = m_command_history.FindString (first_arg);
- if (history_string != NULL)
+ if (history_string != nullptr)
{
matches.Clear();
matches.InsertStringAtIndex(0, history_string);
@@ -2254,7 +2274,7 @@ CommandInterpreter::BuildAliasCommandArgs (CommandObject *alias_cmd_obj,
}
}
- else if (index >= cmd_args.GetArgumentCount())
+ else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount())
{
result.AppendErrorWithFormat
("Not enough arguments provided; you need at least %d arguments to use this alias.\n",
@@ -2364,17 +2384,21 @@ CommandInterpreter::SourceInitFile (bool in_cwd, CommandReturnObject &result)
// "-" and the name of the program. If this file doesn't exist, we fall
// back to just the "~/.lldbinit" file. We also obey any requests to not
// load the init files.
- const char *init_file_path = "~/.lldbinit";
+ llvm::SmallString<64> home_dir_path;
+ llvm::sys::path::home_directory(home_dir_path);
+ FileSpec profilePath(home_dir_path.c_str(), false);
+ profilePath.AppendPathComponent(".lldbinit");
+ std::string init_file_path = profilePath.GetPath();
if (m_skip_app_init_files == false)
{
- FileSpec program_file_spec (Host::GetProgramFileSpec());
+ FileSpec program_file_spec(HostInfo::GetProgramFileSpec());
const char *program_name = program_file_spec.GetFilename().AsCString();
if (program_name)
{
char program_init_file_name[PATH_MAX];
- ::snprintf (program_init_file_name, sizeof(program_init_file_name), "%s-%s", init_file_path, program_name);
+ ::snprintf (program_init_file_name, sizeof(program_init_file_name), "%s-%s", init_file_path.c_str(), program_name);
init_file.SetFile (program_init_file_name, true);
if (!init_file.Exists())
init_file.Clear();
@@ -2382,7 +2406,7 @@ CommandInterpreter::SourceInitFile (bool in_cwd, CommandReturnObject &result)
}
if (!init_file && !m_skip_lldbinit_files)
- init_file.SetFile (init_file_path, true);
+ init_file.SetFile (init_file_path.c_str(), false);
}
// If the file exists, tell HandleCommand to 'source' it; this will do the actual broadcasting
@@ -2392,7 +2416,7 @@ CommandInterpreter::SourceInitFile (bool in_cwd, CommandReturnObject &result)
{
const bool saved_batch = SetBatchCommandMode (true);
HandleCommandsFromFile (init_file,
- NULL, // Execution context
+ nullptr, // Execution context
eLazyBoolYes, // Stop on continue
eLazyBoolNo, // Stop on error
eLazyBoolNo, // Don't echo commands
@@ -2445,7 +2469,7 @@ CommandInterpreter::HandleCommands (const StringList &commands,
// If we've been given an execution context, set it at the start, but don't keep resetting it or we will
// cause series of commands that change the context, then do an operation that relies on that context to fail.
- if (override_context != NULL)
+ if (override_context != nullptr)
UpdateExecutionContext (override_context);
if (!stop_on_continue)
@@ -2475,9 +2499,9 @@ CommandInterpreter::HandleCommands (const StringList &commands,
if (!add_to_history)
m_command_source_depth++;
bool success = HandleCommand(cmd, add_to_history, tmp_result,
- NULL, /* override_context */
+ nullptr, /* override_context */
true, /* repeat_on_empty_command */
- override_context != NULL /* no_context_switching */);
+ override_context != nullptr /* no_context_switching */);
if (!add_to_history)
m_command_source_depth--;
@@ -2490,20 +2514,20 @@ CommandInterpreter::HandleCommands (const StringList &commands,
if (!success || !tmp_result.Succeeded())
{
const char *error_msg = tmp_result.GetErrorData();
- if (error_msg == NULL || error_msg[0] == '\0')
+ if (error_msg == nullptr || error_msg[0] == '\0')
error_msg = "<unknown error>.\n";
if (stop_on_error)
{
- result.AppendErrorWithFormat("Aborting reading of commands after command #%zu: '%s' failed with %s",
- idx, cmd, error_msg);
+ result.AppendErrorWithFormat("Aborting reading of commands after command #%" PRIu64 ": '%s' failed with %s",
+ (uint64_t)idx, cmd, error_msg);
result.SetStatus (eReturnStatusFailed);
m_debugger.SetAsyncExecution (old_async_execution);
return;
}
else if (print_results)
{
- result.AppendMessageWithFormat ("Command #%zu '%s' failed with %s",
- idx + 1,
+ result.AppendMessageWithFormat ("Command #%" PRIu64 " '%s' failed with %s",
+ (uint64_t)idx + 1,
cmd,
error_msg);
}
@@ -2527,10 +2551,10 @@ CommandInterpreter::HandleCommands (const StringList &commands,
// status in our real result before returning. This is an error if the continue was not the
// last command in the set of commands to be run.
if (idx != num_lines - 1)
- result.AppendErrorWithFormat("Aborting reading of commands after command #%zu: '%s' continued the target.\n",
- idx + 1, cmd);
+ result.AppendErrorWithFormat("Aborting reading of commands after command #%" PRIu64 ": '%s' continued the target.\n",
+ (uint64_t)idx + 1, cmd);
else
- result.AppendMessageWithFormat ("Command #%zu '%s' continued the target.\n", idx + 1, cmd);
+ result.AppendMessageWithFormat("Command #%" PRIu64 " '%s' continued the target.\n", (uint64_t)idx + 1, cmd);
result.SetStatus(tmp_result.GetStatus());
m_debugger.SetAsyncExecution (old_async_execution);
@@ -2660,9 +2684,10 @@ CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file,
empty_stream_sp, // Pass in an empty stream so we inherit the top input reader output stream
empty_stream_sp, // Pass in an empty stream so we inherit the top input reader error stream
flags,
- NULL, // Pass in NULL for "editline_name" so no history is saved, or written
+ nullptr, // Pass in NULL for "editline_name" so no history is saved, or written
debugger.GetPrompt(),
false, // Not multi-line
+ 0,
*this));
const bool old_async_execution = debugger.GetAsyncExecution();
@@ -2699,11 +2724,11 @@ CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file,
ScriptInterpreter *
CommandInterpreter::GetScriptInterpreter (bool can_create)
{
- if (m_script_interpreter_ap.get() != NULL)
+ if (m_script_interpreter_ap.get() != nullptr)
return m_script_interpreter_ap.get();
if (!can_create)
- return NULL;
+ return nullptr;
// <rdar://problem/11751427>
// we need to protect the initialization of the script interpreter
@@ -2928,7 +2953,7 @@ CommandInterpreter::FindCommandsForApropos (const char *search_word, StringList
void
CommandInterpreter::UpdateExecutionContext (ExecutionContext *override_context)
{
- if (override_context != NULL)
+ if (override_context != nullptr)
{
m_exe_ctx_ref = *override_context;
}
@@ -3041,6 +3066,24 @@ CommandInterpreter::IOHandlerInputComplete (IOHandler &io_handler, std::string &
}
}
+bool
+CommandInterpreter::IOHandlerInterrupt (IOHandler &io_handler)
+{
+ ExecutionContext exe_ctx (GetExecutionContext());
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (process)
+ {
+ StateType state = process->GetState();
+ if (StateIsRunningState(state))
+ {
+ process->Halt();
+ return true; // Don't do any updating when we are running
+ }
+ }
+ return false;
+}
+
void
CommandInterpreter::GetLLDBCommandsFromIOHandler (const char *prompt,
IOHandlerDelegate &delegate,
@@ -3052,6 +3095,7 @@ CommandInterpreter::GetLLDBCommandsFromIOHandler (const char *prompt,
"lldb", // Name of input reader for history
prompt, // Prompt
true, // Get multiple lines
+ 0, // Don't show line numbers
delegate)); // IOHandlerDelegate
if (io_handler_sp)
@@ -3077,6 +3121,7 @@ CommandInterpreter::GetPythonCommandsFromIOHandler (const char *prompt,
"lldb-python", // Name of input reader for history
prompt, // Prompt
true, // Get multiple lines
+ 0, // Don't show line numbers
delegate)); // IOHandlerDelegate
if (io_handler_sp)
@@ -3100,17 +3145,23 @@ void
CommandInterpreter::RunCommandInterpreter(bool auto_handle_events,
bool spawn_thread)
{
- const bool multiple_lines = false; // Only get one line at a time
- if (!m_command_io_handler_sp)
- m_command_io_handler_sp.reset(new IOHandlerEditline (m_debugger,
- m_debugger.GetInputFile(),
- m_debugger.GetOutputFile(),
- m_debugger.GetErrorFile(),
- eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult,
- "lldb",
- m_debugger.GetPrompt(),
- multiple_lines,
- *this));
+ // Only get one line at a time
+ const bool multiple_lines = false;
+
+ // Always re-create the IOHandlerEditline in case the input
+ // changed. The old instance might have had a non-interactive
+ // input and now it does or vice versa.
+ m_command_io_handler_sp.reset(new IOHandlerEditline (m_debugger,
+ m_debugger.GetInputFile(),
+ m_debugger.GetOutputFile(),
+ m_debugger.GetErrorFile(),
+ eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult,
+ "lldb",
+ m_debugger.GetPrompt(),
+ multiple_lines,
+ 0, // Don't show line numbers
+ *this));
+
m_debugger.PushIOHandler(m_command_io_handler_sp);
if (auto_handle_events)
diff --git a/source/Interpreter/CommandObject.cpp b/source/Interpreter/CommandObject.cpp
index c6995366c87a..3fdbf994fe7a 100644
--- a/source/Interpreter/CommandObject.cpp
+++ b/source/Interpreter/CommandObject.cpp
@@ -56,8 +56,9 @@ CommandObject::CommandObject
m_is_alias (false),
m_flags (flags),
m_arguments(),
- m_command_override_callback (NULL),
- m_command_override_baton (NULL)
+ m_deprecated_command_override_callback (nullptr),
+ m_command_override_callback (nullptr),
+ m_command_override_baton (nullptr)
{
if (help && help[0])
m_cmd_help_short = help;
@@ -88,7 +89,7 @@ CommandObject::GetSyntax ()
{
StreamString syntax_str;
syntax_str.Printf ("%s", GetCommandName());
- if (GetOptions() != NULL)
+ if (GetOptions() != nullptr)
syntax_str.Printf (" <cmd-options>");
if (m_arguments.size() > 0)
{
@@ -144,7 +145,7 @@ CommandObject::GetOptions ()
{
// By default commands don't have options unless this virtual function
// is overridden by base classes.
- return NULL;
+ return nullptr;
}
bool
@@ -156,7 +157,7 @@ CommandObject::ParseOptions
{
// See if the subclass has options?
Options *options = GetOptions();
- if (options != NULL)
+ if (options != nullptr)
{
Error error;
options->NotifyOptionParsingStarting();
@@ -251,7 +252,7 @@ CommandObject::CheckRequirements (CommandReturnObject &result)
return false;
}
- if ((flags & eFlagRequiresRegContext) && (m_exe_ctx.GetRegisterContext() == NULL))
+ if ((flags & eFlagRequiresRegContext) && (m_exe_ctx.GetRegisterContext() == nullptr))
{
result.AppendError (GetInvalidRegContextDescription());
return false;
@@ -268,7 +269,7 @@ CommandObject::CheckRequirements (CommandReturnObject &result)
if (GetFlags().AnySet (CommandObject::eFlagProcessMustBeLaunched | CommandObject::eFlagProcessMustBePaused))
{
Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
- if (process == NULL)
+ if (process == nullptr)
{
// A process that is not running is considered paused.
if (GetFlags().Test(CommandObject::eFlagProcessMustBeLaunched))
@@ -335,7 +336,7 @@ class CommandDictCommandPartialMatch
bool operator() (const std::pair<std::string, lldb::CommandObjectSP> map_element) const
{
// A NULL or empty string matches everything.
- if (m_match_str == NULL || *m_match_str == '\0')
+ if (m_match_str == nullptr || *m_match_str == '\0')
return true;
return map_element.first.find (m_match_str, 0) == 0;
@@ -392,7 +393,7 @@ CommandObject::HandleCompletion
CommandReturnObject result;
OptionElementVector opt_element_vector;
- if (cur_options != NULL)
+ if (cur_options != nullptr)
{
// Re-insert the dummy command name string which will have been
// stripped off:
@@ -453,7 +454,7 @@ CommandObject::HelpTextContainsWord (const char *search_word)
found_word = true;
if (!found_word
- && GetOptions() != NULL)
+ && GetOptions() != nullptr)
{
StreamString usage_help;
GetOptions()->GenerateOptionUsage (usage_help, this);
@@ -477,10 +478,10 @@ CommandObject::GetNumArgumentEntries ()
CommandObject::CommandArgumentEntry *
CommandObject::GetArgumentEntryAtIndex (int idx)
{
- if (idx < m_arguments.size())
+ if (static_cast<size_t>(idx) < m_arguments.size())
return &(m_arguments[idx]);
- return NULL;
+ return nullptr;
}
CommandObject::ArgumentTableEntry *
@@ -492,7 +493,7 @@ CommandObject::FindArgumentDataByType (CommandArgumentType arg_type)
if (table[i].arg_type == arg_type)
return (ArgumentTableEntry *) &(table[i]);
- return NULL;
+ return nullptr;
}
void
@@ -771,7 +772,7 @@ static const char *
FormatHelpTextCallback ()
{
- static char* help_text_ptr = NULL;
+ static char* help_text_ptr = nullptr;
if (help_text_ptr)
return help_text_ptr;
@@ -804,7 +805,7 @@ FormatHelpTextCallback ()
static const char *
LanguageTypeHelpTextCallback ()
{
- static char* help_text_ptr = NULL;
+ static char* help_text_ptr = nullptr;
if (help_text_ptr)
return help_text_ptr;
@@ -900,7 +901,7 @@ void
CommandObject::GenerateHelpText (Stream &output_strm)
{
CommandInterpreter& interpreter = GetCommandInterpreter();
- if (GetOptions() != NULL)
+ if (GetOptions() != nullptr)
{
if (WantsRawCommandString())
{
@@ -913,7 +914,7 @@ CommandObject::GenerateHelpText (Stream &output_strm)
output_strm.Printf ("\nSyntax: %s\n", GetSyntax());
GetOptions()->GenerateOptionUsage (output_strm, this);
const char *long_help = GetHelpLong();
- if ((long_help != NULL)
+ if ((long_help != nullptr)
&& (strlen (long_help) > 0))
output_strm.Printf ("\n%s", long_help);
if (WantsRawCommandString() && !WantsCompletion())
@@ -950,7 +951,7 @@ CommandObject::GenerateHelpText (Stream &output_strm)
else
{
const char *long_help = GetHelpLong();
- if ((long_help != NULL)
+ if ((long_help != nullptr)
&& (strlen (long_help) > 0))
output_strm.Printf ("%s", long_help);
else if (WantsRawCommandString())
@@ -990,7 +991,7 @@ CommandObject::GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_typ
{
if (arg_type >=0 && arg_type < eArgTypeLastArg)
return g_arguments_data[arg_type].arg_name;
- return NULL;
+ return nullptr;
}
@@ -999,20 +1000,19 @@ CommandObject::GetArgumentDescriptionAsCString (const lldb::CommandArgumentType
{
if (arg_type >=0 && arg_type < eArgTypeLastArg)
return g_arguments_data[arg_type].help_text;
- return NULL;
+ return nullptr;
}
bool
CommandObjectParsed::Execute (const char *args_string, CommandReturnObject &result)
{
- CommandOverrideCallback command_callback = GetOverrideCallback();
bool handled = false;
Args cmd_args (args_string);
- if (command_callback)
+ if (HasOverrideCallback())
{
Args full_args (GetCommandName ());
full_args.AppendArguments(cmd_args);
- handled = command_callback (GetOverrideCallbackBaton(), full_args.GetConstArgumentVector());
+ handled = InvokeOverrideCallback (full_args.GetConstArgumentVector(), result);
}
if (!handled)
{
@@ -1040,16 +1040,15 @@ CommandObjectParsed::Execute (const char *args_string, CommandReturnObject &resu
bool
CommandObjectRaw::Execute (const char *args_string, CommandReturnObject &result)
{
- CommandOverrideCallback command_callback = GetOverrideCallback();
bool handled = false;
- if (command_callback)
+ if (HasOverrideCallback())
{
std::string full_command (GetCommandName ());
full_command += ' ';
full_command += args_string;
- const char *argv[2] = { NULL, NULL };
+ const char *argv[2] = { nullptr, nullptr };
argv[0] = full_command.c_str();
- handled = command_callback (GetOverrideCallbackBaton(), argv);
+ handled = InvokeOverrideCallback (argv, result);
}
if (!handled)
{
@@ -1068,7 +1067,7 @@ const char *arch_helper()
if (g_archs_help.Empty())
{
StringList archs;
- ArchSpec::AutoComplete(NULL, archs);
+ ArchSpec::AutoComplete(nullptr, archs);
g_archs_help.Printf("These are the supported architecture names:\n");
archs.Join("\n", g_archs_help);
}
@@ -1078,86 +1077,86 @@ const char *arch_helper()
CommandObject::ArgumentTableEntry
CommandObject::g_arguments_data[] =
{
- { eArgTypeAddress, "address", CommandCompletions::eNoCompletion, { NULL, false }, "A valid address in the target program's execution space." },
- { eArgTypeAddressOrExpression, "address-expression", CommandCompletions::eNoCompletion, { NULL, false }, "An expression that resolves to an address." },
- { eArgTypeAliasName, "alias-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of an abbreviation (alias) for a debugger command." },
- { eArgTypeAliasOptions, "options-for-aliased-command", CommandCompletions::eNoCompletion, { NULL, false }, "Command options to be used as part of an alias (abbreviation) definition. (See 'help commands alias' for more information.)" },
+ { eArgTypeAddress, "address", CommandCompletions::eNoCompletion, { nullptr, false }, "A valid address in the target program's execution space." },
+ { eArgTypeAddressOrExpression, "address-expression", CommandCompletions::eNoCompletion, { nullptr, false }, "An expression that resolves to an address." },
+ { eArgTypeAliasName, "alias-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of an abbreviation (alias) for a debugger command." },
+ { eArgTypeAliasOptions, "options-for-aliased-command", CommandCompletions::eNoCompletion, { nullptr, false }, "Command options to be used as part of an alias (abbreviation) definition. (See 'help commands alias' for more information.)" },
{ eArgTypeArchitecture, "arch", CommandCompletions::eArchitectureCompletion, { arch_helper, true }, "The architecture name, e.g. i386 or x86_64." },
- { eArgTypeBoolean, "boolean", CommandCompletions::eNoCompletion, { NULL, false }, "A Boolean value: 'true' or 'false'" },
- { eArgTypeBreakpointID, "breakpt-id", CommandCompletions::eNoCompletion, { BreakpointIDHelpTextCallback, false }, NULL },
- { eArgTypeBreakpointIDRange, "breakpt-id-list", CommandCompletions::eNoCompletion, { BreakpointIDRangeHelpTextCallback, false }, NULL },
- { eArgTypeByteSize, "byte-size", CommandCompletions::eNoCompletion, { NULL, false }, "Number of bytes to use." },
- { eArgTypeClassName, "class-name", CommandCompletions::eNoCompletion, { NULL, false }, "Then name of a class from the debug information in the program." },
- { eArgTypeCommandName, "cmd-name", CommandCompletions::eNoCompletion, { NULL, false }, "A debugger command (may be multiple words), without any options or arguments." },
- { eArgTypeCount, "count", CommandCompletions::eNoCompletion, { NULL, false }, "An unsigned integer." },
- { eArgTypeDirectoryName, "directory", CommandCompletions::eDiskDirectoryCompletion, { NULL, false }, "A directory name." },
- { eArgTypeDisassemblyFlavor, "disassembly-flavor", CommandCompletions::eNoCompletion, { NULL, false }, "A disassembly flavor recognized by your disassembly plugin. Currently the only valid options are \"att\" and \"intel\" for Intel targets" },
- { eArgTypeDescriptionVerbosity, "description-verbosity", CommandCompletions::eNoCompletion, { NULL, false }, "How verbose the output of 'po' should be." },
- { eArgTypeEndAddress, "end-address", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
- { eArgTypeExpression, "expr", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
- { eArgTypeExpressionPath, "expr-path", CommandCompletions::eNoCompletion, { ExprPathHelpTextCallback, true }, NULL },
- { eArgTypeExprFormat, "expression-format", CommandCompletions::eNoCompletion, { NULL, false }, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]" },
- { eArgTypeFilename, "filename", CommandCompletions::eDiskFileCompletion, { NULL, false }, "The name of a file (can include path)." },
- { eArgTypeFormat, "format", CommandCompletions::eNoCompletion, { FormatHelpTextCallback, true }, NULL },
- { eArgTypeFrameIndex, "frame-index", CommandCompletions::eNoCompletion, { NULL, false }, "Index into a thread's list of frames." },
- { eArgTypeFullName, "fullname", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
- { eArgTypeFunctionName, "function-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a function." },
- { eArgTypeFunctionOrSymbol, "function-or-symbol", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a function or symbol." },
- { eArgTypeGDBFormat, "gdb-format", CommandCompletions::eNoCompletion, { GDBFormatHelpTextCallback, true }, NULL },
- { eArgTypeIndex, "index", CommandCompletions::eNoCompletion, { NULL, false }, "An index into a list." },
- { eArgTypeLanguage, "language", CommandCompletions::eNoCompletion, { LanguageTypeHelpTextCallback, true }, NULL },
- { eArgTypeLineNum, "linenum", CommandCompletions::eNoCompletion, { NULL, false }, "Line number in a source file." },
- { eArgTypeLogCategory, "log-category", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a category within a log channel, e.g. all (try \"log list\" to see a list of all channels and their categories." },
- { eArgTypeLogChannel, "log-channel", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a log channel, e.g. process.gdb-remote (try \"log list\" to see a list of all channels and their categories)." },
- { eArgTypeMethod, "method", CommandCompletions::eNoCompletion, { NULL, false }, "A C++ method name." },
- { eArgTypeName, "name", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
- { eArgTypeNewPathPrefix, "new-path-prefix", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
- { eArgTypeNumLines, "num-lines", CommandCompletions::eNoCompletion, { NULL, false }, "The number of lines to use." },
- { eArgTypeNumberPerLine, "number-per-line", CommandCompletions::eNoCompletion, { NULL, false }, "The number of items per line to display." },
- { eArgTypeOffset, "offset", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
- { eArgTypeOldPathPrefix, "old-path-prefix", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
- { eArgTypeOneLiner, "one-line-command", CommandCompletions::eNoCompletion, { NULL, false }, "A command that is entered as a single line of text." },
- { eArgTypePath, "path", CommandCompletions::eDiskFileCompletion, { NULL, false }, "Path." },
- { eArgTypePermissionsNumber, "perms-numeric", CommandCompletions::eNoCompletion, { NULL, false }, "Permissions given as an octal number (e.g. 755)." },
- { eArgTypePermissionsString, "perms=string", CommandCompletions::eNoCompletion, { NULL, false }, "Permissions given as a string value (e.g. rw-r-xr--)." },
- { eArgTypePid, "pid", CommandCompletions::eNoCompletion, { NULL, false }, "The process ID number." },
- { eArgTypePlugin, "plugin", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
- { eArgTypeProcessName, "process-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of the process." },
- { eArgTypePythonClass, "python-class", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a Python class." },
- { eArgTypePythonFunction, "python-function", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a Python function." },
- { eArgTypePythonScript, "python-script", CommandCompletions::eNoCompletion, { NULL, false }, "Source code written in Python." },
- { eArgTypeQueueName, "queue-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of the thread queue." },
- { eArgTypeRegisterName, "register-name", CommandCompletions::eNoCompletion, { RegisterNameHelpTextCallback, true }, NULL },
- { eArgTypeRegularExpression, "regular-expression", CommandCompletions::eNoCompletion, { NULL, false }, "A regular expression." },
- { eArgTypeRunArgs, "run-args", CommandCompletions::eNoCompletion, { NULL, false }, "Arguments to be passed to the target program when it starts executing." },
- { eArgTypeRunMode, "run-mode", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
- { eArgTypeScriptedCommandSynchronicity, "script-cmd-synchronicity", CommandCompletions::eNoCompletion, { NULL, false }, "The synchronicity to use to run scripted commands with regard to LLDB event system." },
- { eArgTypeScriptLang, "script-language", CommandCompletions::eNoCompletion, { NULL, false }, "The scripting language to be used for script-based commands. Currently only Python is valid." },
- { eArgTypeSearchWord, "search-word", CommandCompletions::eNoCompletion, { NULL, false }, "The word for which you wish to search for information about." },
- { eArgTypeSelector, "selector", CommandCompletions::eNoCompletion, { NULL, false }, "An Objective-C selector name." },
- { eArgTypeSettingIndex, "setting-index", CommandCompletions::eNoCompletion, { NULL, false }, "An index into a settings variable that is an array (try 'settings list' to see all the possible settings variables and their types)." },
- { eArgTypeSettingKey, "setting-key", CommandCompletions::eNoCompletion, { NULL, false }, "A key into a settings variables that is a dictionary (try 'settings list' to see all the possible settings variables and their types)." },
- { eArgTypeSettingPrefix, "setting-prefix", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a settable internal debugger variable up to a dot ('.'), e.g. 'target.process.'" },
- { eArgTypeSettingVariableName, "setting-variable-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a settable internal debugger variable. Type 'settings list' to see a complete list of such variables." },
- { eArgTypeShlibName, "shlib-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a shared library." },
- { eArgTypeSourceFile, "source-file", CommandCompletions::eSourceFileCompletion, { NULL, false }, "The name of a source file.." },
- { eArgTypeSortOrder, "sort-order", CommandCompletions::eNoCompletion, { NULL, false }, "Specify a sort order when dumping lists." },
- { eArgTypeStartAddress, "start-address", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
- { eArgTypeSummaryString, "summary-string", CommandCompletions::eNoCompletion, { SummaryStringHelpTextCallback, true }, NULL },
- { eArgTypeSymbol, "symbol", CommandCompletions::eSymbolCompletion, { NULL, false }, "Any symbol name (function name, variable, argument, etc.)" },
- { eArgTypeThreadID, "thread-id", CommandCompletions::eNoCompletion, { NULL, false }, "Thread ID number." },
- { eArgTypeThreadIndex, "thread-index", CommandCompletions::eNoCompletion, { NULL, false }, "Index into the process' list of threads." },
- { eArgTypeThreadName, "thread-name", CommandCompletions::eNoCompletion, { NULL, false }, "The thread's name." },
- { eArgTypeUnsignedInteger, "unsigned-integer", CommandCompletions::eNoCompletion, { NULL, false }, "An unsigned integer." },
- { eArgTypeUnixSignal, "unix-signal", CommandCompletions::eNoCompletion, { NULL, false }, "A valid Unix signal name or number (e.g. SIGKILL, KILL or 9)." },
- { eArgTypeVarName, "variable-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a variable in your program." },
- { eArgTypeValue, "value", CommandCompletions::eNoCompletion, { NULL, false }, "A value could be anything, depending on where and how it is used." },
- { eArgTypeWidth, "width", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
- { eArgTypeNone, "none", CommandCompletions::eNoCompletion, { NULL, false }, "No help available for this." },
- { eArgTypePlatform, "platform-name", CommandCompletions::ePlatformPluginCompletion, { NULL, false }, "The name of an installed platform plug-in . Type 'platform list' to see a complete list of installed platforms." },
- { eArgTypeWatchpointID, "watchpt-id", CommandCompletions::eNoCompletion, { NULL, false }, "Watchpoint IDs are positive integers." },
- { eArgTypeWatchpointIDRange, "watchpt-id-list", CommandCompletions::eNoCompletion, { NULL, false }, "For example, '1-3' or '1 to 3'." },
- { eArgTypeWatchType, "watch-type", CommandCompletions::eNoCompletion, { NULL, false }, "Specify the type for a watchpoint." }
+ { eArgTypeBoolean, "boolean", CommandCompletions::eNoCompletion, { nullptr, false }, "A Boolean value: 'true' or 'false'" },
+ { eArgTypeBreakpointID, "breakpt-id", CommandCompletions::eNoCompletion, { BreakpointIDHelpTextCallback, false }, nullptr },
+ { eArgTypeBreakpointIDRange, "breakpt-id-list", CommandCompletions::eNoCompletion, { BreakpointIDRangeHelpTextCallback, false }, nullptr },
+ { eArgTypeByteSize, "byte-size", CommandCompletions::eNoCompletion, { nullptr, false }, "Number of bytes to use." },
+ { eArgTypeClassName, "class-name", CommandCompletions::eNoCompletion, { nullptr, false }, "Then name of a class from the debug information in the program." },
+ { eArgTypeCommandName, "cmd-name", CommandCompletions::eNoCompletion, { nullptr, false }, "A debugger command (may be multiple words), without any options or arguments." },
+ { eArgTypeCount, "count", CommandCompletions::eNoCompletion, { nullptr, false }, "An unsigned integer." },
+ { eArgTypeDirectoryName, "directory", CommandCompletions::eDiskDirectoryCompletion, { nullptr, false }, "A directory name." },
+ { eArgTypeDisassemblyFlavor, "disassembly-flavor", CommandCompletions::eNoCompletion, { nullptr, false }, "A disassembly flavor recognized by your disassembly plugin. Currently the only valid options are \"att\" and \"intel\" for Intel targets" },
+ { eArgTypeDescriptionVerbosity, "description-verbosity", CommandCompletions::eNoCompletion, { nullptr, false }, "How verbose the output of 'po' should be." },
+ { eArgTypeEndAddress, "end-address", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." },
+ { eArgTypeExpression, "expr", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." },
+ { eArgTypeExpressionPath, "expr-path", CommandCompletions::eNoCompletion, { ExprPathHelpTextCallback, true }, nullptr },
+ { eArgTypeExprFormat, "expression-format", CommandCompletions::eNoCompletion, { nullptr, false }, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]" },
+ { eArgTypeFilename, "filename", CommandCompletions::eDiskFileCompletion, { nullptr, false }, "The name of a file (can include path)." },
+ { eArgTypeFormat, "format", CommandCompletions::eNoCompletion, { FormatHelpTextCallback, true }, nullptr },
+ { eArgTypeFrameIndex, "frame-index", CommandCompletions::eNoCompletion, { nullptr, false }, "Index into a thread's list of frames." },
+ { eArgTypeFullName, "fullname", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." },
+ { eArgTypeFunctionName, "function-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a function." },
+ { eArgTypeFunctionOrSymbol, "function-or-symbol", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a function or symbol." },
+ { eArgTypeGDBFormat, "gdb-format", CommandCompletions::eNoCompletion, { GDBFormatHelpTextCallback, true }, nullptr },
+ { eArgTypeIndex, "index", CommandCompletions::eNoCompletion, { nullptr, false }, "An index into a list." },
+ { eArgTypeLanguage, "language", CommandCompletions::eNoCompletion, { LanguageTypeHelpTextCallback, true }, nullptr },
+ { eArgTypeLineNum, "linenum", CommandCompletions::eNoCompletion, { nullptr, false }, "Line number in a source file." },
+ { eArgTypeLogCategory, "log-category", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a category within a log channel, e.g. all (try \"log list\" to see a list of all channels and their categories." },
+ { eArgTypeLogChannel, "log-channel", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a log channel, e.g. process.gdb-remote (try \"log list\" to see a list of all channels and their categories)." },
+ { eArgTypeMethod, "method", CommandCompletions::eNoCompletion, { nullptr, false }, "A C++ method name." },
+ { eArgTypeName, "name", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." },
+ { eArgTypeNewPathPrefix, "new-path-prefix", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." },
+ { eArgTypeNumLines, "num-lines", CommandCompletions::eNoCompletion, { nullptr, false }, "The number of lines to use." },
+ { eArgTypeNumberPerLine, "number-per-line", CommandCompletions::eNoCompletion, { nullptr, false }, "The number of items per line to display." },
+ { eArgTypeOffset, "offset", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." },
+ { eArgTypeOldPathPrefix, "old-path-prefix", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." },
+ { eArgTypeOneLiner, "one-line-command", CommandCompletions::eNoCompletion, { nullptr, false }, "A command that is entered as a single line of text." },
+ { eArgTypePath, "path", CommandCompletions::eDiskFileCompletion, { nullptr, false }, "Path." },
+ { eArgTypePermissionsNumber, "perms-numeric", CommandCompletions::eNoCompletion, { nullptr, false }, "Permissions given as an octal number (e.g. 755)." },
+ { eArgTypePermissionsString, "perms=string", CommandCompletions::eNoCompletion, { nullptr, false }, "Permissions given as a string value (e.g. rw-r-xr--)." },
+ { eArgTypePid, "pid", CommandCompletions::eNoCompletion, { nullptr, false }, "The process ID number." },
+ { eArgTypePlugin, "plugin", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." },
+ { eArgTypeProcessName, "process-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of the process." },
+ { eArgTypePythonClass, "python-class", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a Python class." },
+ { eArgTypePythonFunction, "python-function", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a Python function." },
+ { eArgTypePythonScript, "python-script", CommandCompletions::eNoCompletion, { nullptr, false }, "Source code written in Python." },
+ { eArgTypeQueueName, "queue-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of the thread queue." },
+ { eArgTypeRegisterName, "register-name", CommandCompletions::eNoCompletion, { RegisterNameHelpTextCallback, true }, nullptr },
+ { eArgTypeRegularExpression, "regular-expression", CommandCompletions::eNoCompletion, { nullptr, false }, "A regular expression." },
+ { eArgTypeRunArgs, "run-args", CommandCompletions::eNoCompletion, { nullptr, false }, "Arguments to be passed to the target program when it starts executing." },
+ { eArgTypeRunMode, "run-mode", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." },
+ { eArgTypeScriptedCommandSynchronicity, "script-cmd-synchronicity", CommandCompletions::eNoCompletion, { nullptr, false }, "The synchronicity to use to run scripted commands with regard to LLDB event system." },
+ { eArgTypeScriptLang, "script-language", CommandCompletions::eNoCompletion, { nullptr, false }, "The scripting language to be used for script-based commands. Currently only Python is valid." },
+ { eArgTypeSearchWord, "search-word", CommandCompletions::eNoCompletion, { nullptr, false }, "The word for which you wish to search for information about." },
+ { eArgTypeSelector, "selector", CommandCompletions::eNoCompletion, { nullptr, false }, "An Objective-C selector name." },
+ { eArgTypeSettingIndex, "setting-index", CommandCompletions::eNoCompletion, { nullptr, false }, "An index into a settings variable that is an array (try 'settings list' to see all the possible settings variables and their types)." },
+ { eArgTypeSettingKey, "setting-key", CommandCompletions::eNoCompletion, { nullptr, false }, "A key into a settings variables that is a dictionary (try 'settings list' to see all the possible settings variables and their types)." },
+ { eArgTypeSettingPrefix, "setting-prefix", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a settable internal debugger variable up to a dot ('.'), e.g. 'target.process.'" },
+ { eArgTypeSettingVariableName, "setting-variable-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a settable internal debugger variable. Type 'settings list' to see a complete list of such variables." },
+ { eArgTypeShlibName, "shlib-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a shared library." },
+ { eArgTypeSourceFile, "source-file", CommandCompletions::eSourceFileCompletion, { nullptr, false }, "The name of a source file.." },
+ { eArgTypeSortOrder, "sort-order", CommandCompletions::eNoCompletion, { nullptr, false }, "Specify a sort order when dumping lists." },
+ { eArgTypeStartAddress, "start-address", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." },
+ { eArgTypeSummaryString, "summary-string", CommandCompletions::eNoCompletion, { SummaryStringHelpTextCallback, true }, nullptr },
+ { eArgTypeSymbol, "symbol", CommandCompletions::eSymbolCompletion, { nullptr, false }, "Any symbol name (function name, variable, argument, etc.)" },
+ { eArgTypeThreadID, "thread-id", CommandCompletions::eNoCompletion, { nullptr, false }, "Thread ID number." },
+ { eArgTypeThreadIndex, "thread-index", CommandCompletions::eNoCompletion, { nullptr, false }, "Index into the process' list of threads." },
+ { eArgTypeThreadName, "thread-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The thread's name." },
+ { eArgTypeUnsignedInteger, "unsigned-integer", CommandCompletions::eNoCompletion, { nullptr, false }, "An unsigned integer." },
+ { eArgTypeUnixSignal, "unix-signal", CommandCompletions::eNoCompletion, { nullptr, false }, "A valid Unix signal name or number (e.g. SIGKILL, KILL or 9)." },
+ { eArgTypeVarName, "variable-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a variable in your program." },
+ { eArgTypeValue, "value", CommandCompletions::eNoCompletion, { nullptr, false }, "A value could be anything, depending on where and how it is used." },
+ { eArgTypeWidth, "width", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." },
+ { eArgTypeNone, "none", CommandCompletions::eNoCompletion, { nullptr, false }, "No help available for this." },
+ { eArgTypePlatform, "platform-name", CommandCompletions::ePlatformPluginCompletion, { nullptr, false }, "The name of an installed platform plug-in . Type 'platform list' to see a complete list of installed platforms." },
+ { eArgTypeWatchpointID, "watchpt-id", CommandCompletions::eNoCompletion, { nullptr, false }, "Watchpoint IDs are positive integers." },
+ { eArgTypeWatchpointIDRange, "watchpt-id-list", CommandCompletions::eNoCompletion, { nullptr, false }, "For example, '1-3' or '1 to 3'." },
+ { eArgTypeWatchType, "watch-type", CommandCompletions::eNoCompletion, { nullptr, false }, "Specify the type for a watchpoint." }
};
const CommandObject::ArgumentTableEntry*
diff --git a/source/Interpreter/CommandObjectRegexCommand.cpp b/source/Interpreter/CommandObjectRegexCommand.cpp
index 59cf1f05fb65..d27320dd1f3d 100644
--- a/source/Interpreter/CommandObjectRegexCommand.cpp
+++ b/source/Interpreter/CommandObjectRegexCommand.cpp
@@ -86,11 +86,11 @@ CommandObjectRegexCommand::DoExecute
result.GetOutputStream().Printf("%s\n", new_command.c_str());
// Pass in true for "no context switching". The command that called us should have set up the context
// appropriately, we shouldn't have to redo that.
- return m_interpreter.HandleCommand(new_command.c_str(), eLazyBoolCalculate, result, NULL, true, true);
+ return m_interpreter.HandleCommand(new_command.c_str(), eLazyBoolCalculate, result, nullptr, true, true);
}
}
result.SetStatus(eReturnStatusFailed);
- if (GetSyntax() != NULL)
+ if (GetSyntax() != nullptr)
result.AppendError (GetSyntax());
else
result.AppendErrorWithFormat ("Command contents '%s' failed to match any regular expression in the '%s' regex command.\n",
@@ -136,7 +136,7 @@ CommandObjectRegexCommand::HandleCompletion (Args &input,
completion_str.c_str(),
match_start_point,
max_return_elements,
- NULL,
+ nullptr,
word_complete,
matches);
return matches.GetSize();
diff --git a/source/Interpreter/CommandObjectScript.cpp b/source/Interpreter/CommandObjectScript.cpp
index aff507d98580..9c67e4253301 100644
--- a/source/Interpreter/CommandObjectScript.cpp
+++ b/source/Interpreter/CommandObjectScript.cpp
@@ -66,7 +66,7 @@ CommandObjectScript::DoExecute
ScriptInterpreter *script_interpreter = m_interpreter.GetScriptInterpreter ();
- if (script_interpreter == NULL)
+ if (script_interpreter == nullptr)
{
result.AppendError("no script interpreter");
result.SetStatus (eReturnStatusFailed);
@@ -75,7 +75,7 @@ CommandObjectScript::DoExecute
DataVisualization::ForceUpdate(); // script might change Python code we use for formatting.. make sure we keep up to date with it
- if (command == NULL || command[0] == '\0')
+ if (command == nullptr || command[0] == '\0')
{
script_interpreter->ExecuteInterpreterLoop ();
result.SetStatus (eReturnStatusSuccessFinishNoResult);
diff --git a/source/Interpreter/CommandOptionValidators.cpp b/source/Interpreter/CommandOptionValidators.cpp
new file mode 100644
index 000000000000..7d66de53c0b4
--- /dev/null
+++ b/source/Interpreter/CommandOptionValidators.cpp
@@ -0,0 +1,39 @@
+//===-- CommandOptionValidators.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/Interpreter/CommandOptionValidators.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/Platform.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool PosixPlatformCommandOptionValidator::IsValid(Platform &platform, const ExecutionContext &target) const
+{
+ llvm::Triple::OSType os = platform.GetSystemArchitecture().GetTriple().getOS();
+ switch (os)
+ {
+ // Are there any other platforms that are not POSIX-compatible?
+ case llvm::Triple::Win32:
+ return false;
+ default:
+ return true;
+ }
+}
+
+const char* PosixPlatformCommandOptionValidator::ShortConditionString() const
+{
+ return "POSIX";
+}
+
+const char* PosixPlatformCommandOptionValidator::LongConditionString() const
+{
+ return "Option only valid for POSIX-compliant hosts.";
+}
diff --git a/source/Interpreter/CommandReturnObject.cpp b/source/Interpreter/CommandReturnObject.cpp
index 9c63753a23ff..1b5418735069 100644
--- a/source/Interpreter/CommandReturnObject.cpp
+++ b/source/Interpreter/CommandReturnObject.cpp
@@ -46,7 +46,8 @@ CommandReturnObject::CommandReturnObject () :
m_out_stream (),
m_err_stream (),
m_status (eReturnStatusStarted),
- m_did_change_process_state (false)
+ m_did_change_process_state (false),
+ m_interactive (true)
{
}
@@ -141,7 +142,7 @@ void
CommandReturnObject::SetError (const Error &error, const char *fallback_error_cstr)
{
const char *error_cstr = error.AsCString();
- if (error_cstr == NULL)
+ if (error_cstr == nullptr)
error_cstr = fallback_error_cstr;
SetError(error_cstr);
}
@@ -203,6 +204,7 @@ CommandReturnObject::Clear()
static_cast<StreamString *>(stream_sp.get())->Clear();
m_status = eReturnStatusStarted;
m_did_change_process_state = false;
+ m_interactive = true;
}
bool
@@ -217,3 +219,17 @@ CommandReturnObject::SetDidChangeProcessState (bool b)
m_did_change_process_state = b;
}
+
+bool
+CommandReturnObject::GetInteractive () const
+{
+ return m_interactive;
+}
+
+void
+CommandReturnObject::SetInteractive (bool b)
+{
+ m_interactive = b;
+}
+
+
diff --git a/source/Interpreter/OptionGroupArchitecture.cpp b/source/Interpreter/OptionGroupArchitecture.cpp
index d8f35675fbab..3a454093ab29 100644
--- a/source/Interpreter/OptionGroupArchitecture.cpp
+++ b/source/Interpreter/OptionGroupArchitecture.cpp
@@ -30,7 +30,7 @@ OptionGroupArchitecture::~OptionGroupArchitecture ()
static OptionDefinition
g_option_table[] =
{
- { LLDB_OPT_SET_1 , false, "arch" , 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeArchitecture , "Specify the architecture for the target."},
+ { LLDB_OPT_SET_1 , false, "arch" , 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeArchitecture , "Specify the architecture for the target."},
};
uint32_t
diff --git a/source/Interpreter/OptionGroupBoolean.cpp b/source/Interpreter/OptionGroupBoolean.cpp
index feb135315e1b..0c502cc364b4 100644
--- a/source/Interpreter/OptionGroupBoolean.cpp
+++ b/source/Interpreter/OptionGroupBoolean.cpp
@@ -30,8 +30,9 @@ OptionGroupBoolean::OptionGroupBoolean (uint32_t usage_mask,
m_option_definition.required = required;
m_option_definition.long_option = long_option;
m_option_definition.short_option = short_option;
+ m_option_definition.validator = nullptr;
m_option_definition.option_has_arg = no_argument_toggle_default ? OptionParser::eNoArgument : OptionParser::eRequiredArgument;
- m_option_definition.enum_values = NULL;
+ m_option_definition.enum_values = nullptr;
m_option_definition.completion_type = 0;
m_option_definition.argument_type = eArgTypeBoolean;
m_option_definition.usage_text = usage_text;
diff --git a/source/Interpreter/OptionGroupFile.cpp b/source/Interpreter/OptionGroupFile.cpp
index 48469a80417e..9bfe8ddf0282 100644
--- a/source/Interpreter/OptionGroupFile.cpp
+++ b/source/Interpreter/OptionGroupFile.cpp
@@ -30,8 +30,9 @@ OptionGroupFile::OptionGroupFile (uint32_t usage_mask,
m_option_definition.required = required;
m_option_definition.long_option = long_option;
m_option_definition.short_option = short_option;
+ m_option_definition.validator = nullptr;
m_option_definition.option_has_arg = OptionParser::eRequiredArgument;
- m_option_definition.enum_values = NULL;
+ m_option_definition.enum_values = nullptr;
m_option_definition.completion_type = completion_type;
m_option_definition.argument_type = argument_type;
m_option_definition.usage_text = usage_text;
@@ -70,8 +71,9 @@ OptionGroupFileList::OptionGroupFileList (uint32_t usage_mask,
m_option_definition.required = required;
m_option_definition.long_option = long_option;
m_option_definition.short_option = short_option;
+ m_option_definition.validator = nullptr;
m_option_definition.option_has_arg = OptionParser::eRequiredArgument;
- m_option_definition.enum_values = NULL;
+ m_option_definition.enum_values = nullptr;
m_option_definition.completion_type = completion_type;
m_option_definition.argument_type = argument_type;
m_option_definition.usage_text = usage_text;
diff --git a/source/Interpreter/OptionGroupFormat.cpp b/source/Interpreter/OptionGroupFormat.cpp
index 5cae3788f3bf..601a78458730 100644
--- a/source/Interpreter/OptionGroupFormat.cpp
+++ b/source/Interpreter/OptionGroupFormat.cpp
@@ -42,10 +42,10 @@ OptionGroupFormat::~OptionGroupFormat ()
static OptionDefinition
g_option_table[] =
{
-{ LLDB_OPT_SET_1, false, "format" ,'f', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFormat , "Specify a format to be used for display."},
-{ LLDB_OPT_SET_2, false, "gdb-format",'G', OptionParser::eRequiredArgument, NULL, 0, eArgTypeGDBFormat, "Specify a format using a GDB format specifier string."},
-{ LLDB_OPT_SET_3, false, "size" ,'s', OptionParser::eRequiredArgument, NULL, 0, eArgTypeByteSize , "The size in bytes to use when displaying with the selected format."},
-{ LLDB_OPT_SET_4, false, "count" ,'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount , "The number of total items to display."},
+{ LLDB_OPT_SET_1, false, "format" ,'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFormat , "Specify a format to be used for display."},
+{ LLDB_OPT_SET_2, false, "gdb-format",'G', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeGDBFormat, "Specify a format using a GDB format specifier string."},
+{ LLDB_OPT_SET_3, false, "size" ,'s', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeByteSize , "The size in bytes to use when displaying with the selected format."},
+{ LLDB_OPT_SET_4, false, "count" ,'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount , "The number of total items to display."},
};
uint32_t
@@ -109,7 +109,7 @@ OptionGroupFormat::SetOptionValue (CommandInterpreter &interpreter,
case 'G':
{
- char *end = NULL;
+ char *end = nullptr;
const char *gdb_format_cstr = option_arg;
uint64_t count = 0;
if (::isdigit (gdb_format_cstr[0]))
diff --git a/source/Interpreter/OptionGroupOutputFile.cpp b/source/Interpreter/OptionGroupOutputFile.cpp
index 3bb8ab3b29cb..ec9e166d2f05 100644
--- a/source/Interpreter/OptionGroupOutputFile.cpp
+++ b/source/Interpreter/OptionGroupOutputFile.cpp
@@ -28,11 +28,15 @@ OptionGroupOutputFile::~OptionGroupOutputFile ()
{
}
+static const uint32_t SHORT_OPTION_APND = 0x61706e64; // 'apnd'
+
static OptionDefinition
g_option_table[] =
{
- { LLDB_OPT_SET_1 , false, "outfile", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename , "Specify a path for capturing command output."},
- { LLDB_OPT_SET_1 , false, "append-outfile" , 'apnd', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Append to the the file specified with '--outfile <path>'."},
+ { LLDB_OPT_SET_1 , false, "outfile", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFilename , "Specify a path for capturing command output."},
+ { LLDB_OPT_SET_1 , false, "append-outfile" , SHORT_OPTION_APND,
+ OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone ,
+ "Append to the the file specified with '--outfile <path>'."},
};
uint32_t
@@ -61,7 +65,7 @@ OptionGroupOutputFile::SetOptionValue (CommandInterpreter &interpreter,
error = m_file.SetValueFromCString (option_arg);
break;
- case 'apnd':
+ case SHORT_OPTION_APND:
m_append.SetCurrentValue(true);
break;
diff --git a/source/Interpreter/OptionGroupPlatform.cpp b/source/Interpreter/OptionGroupPlatform.cpp
index 83e28bdd02c1..9ffd5f072d90 100644
--- a/source/Interpreter/OptionGroupPlatform.cpp
+++ b/source/Interpreter/OptionGroupPlatform.cpp
@@ -85,10 +85,10 @@ OptionGroupPlatform::OptionParsingStarting (CommandInterpreter &interpreter)
static OptionDefinition
g_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "platform", 'p', OptionParser::eRequiredArgument, NULL, 0, eArgTypePlatform, "Specify name of the platform to use for this target, creating the platform if necessary."},
- { LLDB_OPT_SET_ALL, false, "version" , 'v', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNone, "Specify the initial SDK version to use prior to connecting." },
- { LLDB_OPT_SET_ALL, false, "build" , 'b', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNone, "Specify the initial SDK build number." },
- { LLDB_OPT_SET_ALL, false, "sysroot" , 'S', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename, "Specify the SDK root directory that contains a root of all remote system files." }
+ { LLDB_OPT_SET_ALL, false, "platform", 'p', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePlatform, "Specify name of the platform to use for this target, creating the platform if necessary."},
+ { LLDB_OPT_SET_ALL, false, "version" , 'v', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "Specify the initial SDK version to use prior to connecting." },
+ { LLDB_OPT_SET_ALL, false, "build" , 'b', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "Specify the initial SDK build number." },
+ { LLDB_OPT_SET_ALL, false, "sysroot" , 'S', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFilename, "Specify the SDK root directory that contains a root of all remote system files." }
};
const OptionDefinition*
diff --git a/source/Interpreter/OptionGroupString.cpp b/source/Interpreter/OptionGroupString.cpp
index 37a70d0bb242..9bc1c94d3a5a 100644
--- a/source/Interpreter/OptionGroupString.cpp
+++ b/source/Interpreter/OptionGroupString.cpp
@@ -31,8 +31,9 @@ OptionGroupString::OptionGroupString (uint32_t usage_mask,
m_option_definition.required = required;
m_option_definition.long_option = long_option;
m_option_definition.short_option = short_option;
+ m_option_definition.validator = nullptr;
m_option_definition.option_has_arg = OptionParser::eRequiredArgument;
- m_option_definition.enum_values = NULL;
+ m_option_definition.enum_values = nullptr;
m_option_definition.completion_type = completion_type;
m_option_definition.argument_type = argument_type;
m_option_definition.usage_text = usage_text;
diff --git a/source/Interpreter/OptionGroupUInt64.cpp b/source/Interpreter/OptionGroupUInt64.cpp
index b66c84579232..440c2a740c26 100644
--- a/source/Interpreter/OptionGroupUInt64.cpp
+++ b/source/Interpreter/OptionGroupUInt64.cpp
@@ -31,8 +31,9 @@ OptionGroupUInt64::OptionGroupUInt64 (uint32_t usage_mask,
m_option_definition.required = required;
m_option_definition.long_option = long_option;
m_option_definition.short_option = short_option;
+ m_option_definition.validator = nullptr;
m_option_definition.option_has_arg = OptionParser::eRequiredArgument;
- m_option_definition.enum_values = NULL;
+ m_option_definition.enum_values = nullptr;
m_option_definition.completion_type = completion_type;
m_option_definition.argument_type = argument_type;
m_option_definition.usage_text = usage_text;
diff --git a/source/Interpreter/OptionGroupUUID.cpp b/source/Interpreter/OptionGroupUUID.cpp
index fb3ebcf7745c..43f7386c9ca6 100644
--- a/source/Interpreter/OptionGroupUUID.cpp
+++ b/source/Interpreter/OptionGroupUUID.cpp
@@ -30,7 +30,7 @@ OptionGroupUUID::~OptionGroupUUID ()
static OptionDefinition
g_option_table[] =
{
- { LLDB_OPT_SET_1 , false, "uuid", 'u', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNone, "A module UUID value."},
+ { LLDB_OPT_SET_1 , false, "uuid", 'u', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "A module UUID value."},
};
uint32_t
diff --git a/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/source/Interpreter/OptionGroupValueObjectDisplay.cpp
index c79f49dc1d94..125e5fb0a5d6 100644
--- a/source/Interpreter/OptionGroupValueObjectDisplay.cpp
+++ b/source/Interpreter/OptionGroupValueObjectDisplay.cpp
@@ -34,18 +34,18 @@ OptionGroupValueObjectDisplay::~OptionGroupValueObjectDisplay ()
static OptionDefinition
g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "dynamic-type", 'd', OptionParser::eRequiredArgument, g_dynamic_value_types, 0, eArgTypeNone, "Show the object as its full dynamic type, not its static type, if available."},
- { LLDB_OPT_SET_1, false, "synthetic-type", 'S', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Show the object obeying its synthetic provider, if available."},
- { LLDB_OPT_SET_1, false, "depth", 'D', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount, "Set the max recurse depth when dumping aggregate types (default is infinity)."},
- { LLDB_OPT_SET_1, false, "flat", 'F', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Display results in a flat format that uses expression paths for each variable or member."},
- { LLDB_OPT_SET_1, false, "location", 'L', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Show variable location information."},
- { LLDB_OPT_SET_1, false, "object-description", 'O', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Print as an Objective-C object."},
- { LLDB_OPT_SET_1, false, "ptr-depth", 'P', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount, "The number of pointers to be traversed when dumping values (default is zero)."},
- { LLDB_OPT_SET_1, false, "show-types", 'T', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Show variable types when dumping values."},
- { LLDB_OPT_SET_1, false, "no-summary-depth", 'Y', OptionParser::eOptionalArgument, NULL, 0, eArgTypeCount, "Set the depth at which omitting summary information stops (default is 1)."},
- { LLDB_OPT_SET_1, false, "raw-output", 'R', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't use formatting options."},
- { LLDB_OPT_SET_1, false, "show-all-children", 'A', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Ignore the upper bound on the number of children to show."},
- { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+ { LLDB_OPT_SET_1, false, "dynamic-type", 'd', OptionParser::eRequiredArgument, nullptr, g_dynamic_value_types, 0, eArgTypeNone, "Show the object as its full dynamic type, not its static type, if available."},
+ { LLDB_OPT_SET_1, false, "synthetic-type", 'S', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Show the object obeying its synthetic provider, if available."},
+ { LLDB_OPT_SET_1, false, "depth", 'D', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "Set the max recurse depth when dumping aggregate types (default is infinity)."},
+ { LLDB_OPT_SET_1, false, "flat", 'F', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display results in a flat format that uses expression paths for each variable or member."},
+ { LLDB_OPT_SET_1, false, "location", 'L', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Show variable location information."},
+ { LLDB_OPT_SET_1, false, "object-description", 'O', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Print as an Objective-C object."},
+ { LLDB_OPT_SET_1, false, "ptr-depth", 'P', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "The number of pointers to be traversed when dumping values (default is zero)."},
+ { LLDB_OPT_SET_1, false, "show-types", 'T', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Show variable types when dumping values."},
+ { LLDB_OPT_SET_1, false, "no-summary-depth", 'Y', OptionParser::eOptionalArgument, nullptr, nullptr, 0, eArgTypeCount, "Set the depth at which omitting summary information stops (default is 1)."},
+ { LLDB_OPT_SET_1, false, "raw-output", 'R', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use formatting options."},
+ { LLDB_OPT_SET_1, false, "show-all-children", 'A', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Ignore the upper bound on the number of children to show."},
+ { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr }
};
uint32_t
@@ -139,7 +139,7 @@ OptionGroupValueObjectDisplay::OptionParsingStarting (CommandInterpreter &interp
ignore_cap = false;
Target *target = interpreter.GetExecutionContext().GetTargetPtr();
- if (target != NULL)
+ if (target != nullptr)
use_dynamic = target->GetPreferDynamicValue();
else
{
diff --git a/source/Interpreter/OptionGroupVariable.cpp b/source/Interpreter/OptionGroupVariable.cpp
index 31c2547e2c37..05cf3f73bfed 100644
--- a/source/Interpreter/OptionGroupVariable.cpp
+++ b/source/Interpreter/OptionGroupVariable.cpp
@@ -28,14 +28,14 @@ using namespace lldb_private;
static OptionDefinition
g_option_table[] =
{
- { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-args", 'a', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Omit function arguments."},
- { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-locals", 'l', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Omit local variables."},
- { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "show-globals", 'g', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Show the current frame source file global and static variables."},
- { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "show-declaration",'c', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Show variable declaration information (source file and line where the variable was declared)."},
- { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "regex", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeRegularExpression, "The <variable-name> argument for name lookups are regular expressions."},
- { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "scope", 's', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Show variable scope (argument, local, global, static)."},
- { LLDB_OPT_SET_1, false, "summary", 'y', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Specify the summary that the variable output should use."},
- { LLDB_OPT_SET_2, false, "summary-string", 'z', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Specify a summary string to use to format the variable output."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-args", 'a', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Omit function arguments."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-locals", 'l', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Omit local variables."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "show-globals", 'g', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Show the current frame source file global and static variables."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "show-declaration",'c', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Show variable declaration information (source file and line where the variable was declared)."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "regex", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeRegularExpression, "The <variable-name> argument for name lookups are regular expressions."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "scope", 's', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Show variable scope (argument, local, global, static)."},
+ { LLDB_OPT_SET_1, false, "summary", 'y', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Specify the summary that the variable output should use."},
+ { LLDB_OPT_SET_2, false, "summary-string", 'z', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Specify a summary string to use to format the variable output."},
};
static Error
diff --git a/source/Interpreter/OptionGroupWatchpoint.cpp b/source/Interpreter/OptionGroupWatchpoint.cpp
index 09dc8ed88d2f..f4d8df1e6ba7 100644
--- a/source/Interpreter/OptionGroupWatchpoint.cpp
+++ b/source/Interpreter/OptionGroupWatchpoint.cpp
@@ -25,7 +25,7 @@ static OptionEnumValueElement g_watch_type[] =
{ OptionGroupWatchpoint::eWatchRead, "read", "Watch for read"},
{ OptionGroupWatchpoint::eWatchWrite, "write", "Watch for write"},
{ OptionGroupWatchpoint::eWatchReadWrite, "read_write", "Watch for read/write"},
- { 0, NULL, NULL }
+ { 0, nullptr, nullptr }
};
static OptionEnumValueElement g_watch_size[] =
@@ -34,14 +34,14 @@ static OptionEnumValueElement g_watch_size[] =
{ 2, "2", "Watch for byte size of 2"},
{ 4, "4", "Watch for byte size of 4"},
{ 8, "8", "Watch for byte size of 8"},
- { 0, NULL, NULL }
+ { 0, nullptr, nullptr }
};
static OptionDefinition
g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "watch", 'w', OptionParser::eRequiredArgument, g_watch_type, 0, eArgTypeWatchType, "Specify the type of watching to perform."},
- { LLDB_OPT_SET_1, false, "xsize", 'x', OptionParser::eRequiredArgument, g_watch_size, 0, eArgTypeByteSize, "Number of bytes to use to watch a region."}
+ { LLDB_OPT_SET_1, false, "watch", 'w', OptionParser::eRequiredArgument, nullptr, g_watch_type, 0, eArgTypeWatchType, "Specify the type of watching to perform."},
+ { LLDB_OPT_SET_1, false, "xsize", 'x', OptionParser::eRequiredArgument, nullptr, g_watch_size, 0, eArgTypeByteSize, "Number of bytes to use to watch a region."}
};
diff --git a/source/Interpreter/OptionValue.cpp b/source/Interpreter/OptionValue.cpp
index 1f6b03ddac1a..bc1e1c4c4779 100644
--- a/source/Interpreter/OptionValue.cpp
+++ b/source/Interpreter/OptionValue.cpp
@@ -60,7 +60,7 @@ OptionValue::GetAsBoolean ()
{
if (GetType () == OptionValue::eTypeBoolean)
return static_cast<OptionValueBoolean *>(this);
- return NULL;
+ return nullptr;
}
const OptionValueBoolean *
@@ -68,7 +68,7 @@ OptionValue::GetAsBoolean () const
{
if (GetType () == OptionValue::eTypeBoolean)
return static_cast<const OptionValueBoolean *>(this);
- return NULL;
+ return nullptr;
}
@@ -77,7 +77,7 @@ OptionValue::GetAsFileSpec ()
{
if (GetType () == OptionValue::eTypeFileSpec)
return static_cast<OptionValueFileSpec *>(this);
- return NULL;
+ return nullptr;
}
@@ -86,7 +86,7 @@ OptionValue::GetAsFileSpec () const
{
if (GetType () == OptionValue::eTypeFileSpec)
return static_cast<const OptionValueFileSpec *>(this);
- return NULL;
+ return nullptr;
}
@@ -95,7 +95,7 @@ OptionValue::GetAsFileSpecList ()
{
if (GetType () == OptionValue::eTypeFileSpecList)
return static_cast<OptionValueFileSpecList *>(this);
- return NULL;
+ return nullptr;
}
@@ -104,7 +104,7 @@ OptionValue::GetAsFileSpecList () const
{
if (GetType () == OptionValue::eTypeFileSpecList)
return static_cast<const OptionValueFileSpecList *>(this);
- return NULL;
+ return nullptr;
}
@@ -113,7 +113,7 @@ OptionValue::GetAsArch ()
{
if (GetType () == OptionValue::eTypeArch)
return static_cast<OptionValueArch *>(this);
- return NULL;
+ return nullptr;
}
@@ -122,7 +122,7 @@ OptionValue::GetAsArch () const
{
if (GetType () == OptionValue::eTypeArch)
return static_cast<const OptionValueArch *>(this);
- return NULL;
+ return nullptr;
}
OptionValueArray *
@@ -130,7 +130,7 @@ OptionValue::GetAsArray ()
{
if (GetType () == OptionValue::eTypeArray)
return static_cast<OptionValueArray *>(this);
- return NULL;
+ return nullptr;
}
@@ -139,7 +139,7 @@ OptionValue::GetAsArray () const
{
if (GetType () == OptionValue::eTypeArray)
return static_cast<const OptionValueArray *>(this);
- return NULL;
+ return nullptr;
}
OptionValueArgs *
@@ -147,7 +147,7 @@ OptionValue::GetAsArgs ()
{
if (GetType () == OptionValue::eTypeArgs)
return static_cast<OptionValueArgs *>(this);
- return NULL;
+ return nullptr;
}
@@ -156,7 +156,7 @@ OptionValue::GetAsArgs () const
{
if (GetType () == OptionValue::eTypeArgs)
return static_cast<const OptionValueArgs *>(this);
- return NULL;
+ return nullptr;
}
OptionValueDictionary *
@@ -164,7 +164,7 @@ OptionValue::GetAsDictionary ()
{
if (GetType () == OptionValue::eTypeDictionary)
return static_cast<OptionValueDictionary *>(this);
- return NULL;
+ return nullptr;
}
const OptionValueDictionary *
@@ -172,7 +172,7 @@ OptionValue::GetAsDictionary () const
{
if (GetType () == OptionValue::eTypeDictionary)
return static_cast<const OptionValueDictionary *>(this);
- return NULL;
+ return nullptr;
}
OptionValueEnumeration *
@@ -180,7 +180,7 @@ OptionValue::GetAsEnumeration ()
{
if (GetType () == OptionValue::eTypeEnum)
return static_cast<OptionValueEnumeration *>(this);
- return NULL;
+ return nullptr;
}
const OptionValueEnumeration *
@@ -188,7 +188,7 @@ OptionValue::GetAsEnumeration () const
{
if (GetType () == OptionValue::eTypeEnum)
return static_cast<const OptionValueEnumeration *>(this);
- return NULL;
+ return nullptr;
}
OptionValueFormat *
@@ -196,7 +196,7 @@ OptionValue::GetAsFormat ()
{
if (GetType () == OptionValue::eTypeFormat)
return static_cast<OptionValueFormat *>(this);
- return NULL;
+ return nullptr;
}
const OptionValueFormat *
@@ -204,7 +204,7 @@ OptionValue::GetAsFormat () const
{
if (GetType () == OptionValue::eTypeFormat)
return static_cast<const OptionValueFormat *>(this);
- return NULL;
+ return nullptr;
}
OptionValuePathMappings *
@@ -212,7 +212,7 @@ OptionValue::GetAsPathMappings ()
{
if (GetType () == OptionValue::eTypePathMap)
return static_cast<OptionValuePathMappings *>(this);
- return NULL;
+ return nullptr;
}
const OptionValuePathMappings *
@@ -220,7 +220,7 @@ OptionValue::GetAsPathMappings () const
{
if (GetType () == OptionValue::eTypePathMap)
return static_cast<const OptionValuePathMappings *>(this);
- return NULL;
+ return nullptr;
}
OptionValueProperties *
@@ -228,7 +228,7 @@ OptionValue::GetAsProperties ()
{
if (GetType () == OptionValue::eTypeProperties)
return static_cast<OptionValueProperties *>(this);
- return NULL;
+ return nullptr;
}
const OptionValueProperties *
@@ -236,7 +236,7 @@ OptionValue::GetAsProperties () const
{
if (GetType () == OptionValue::eTypeProperties)
return static_cast<const OptionValueProperties *>(this);
- return NULL;
+ return nullptr;
}
OptionValueRegex *
@@ -244,7 +244,7 @@ OptionValue::GetAsRegex ()
{
if (GetType () == OptionValue::eTypeRegex)
return static_cast<OptionValueRegex *>(this);
- return NULL;
+ return nullptr;
}
const OptionValueRegex *
@@ -252,7 +252,7 @@ OptionValue::GetAsRegex () const
{
if (GetType () == OptionValue::eTypeRegex)
return static_cast<const OptionValueRegex *>(this);
- return NULL;
+ return nullptr;
}
OptionValueSInt64 *
@@ -260,7 +260,7 @@ OptionValue::GetAsSInt64 ()
{
if (GetType () == OptionValue::eTypeSInt64)
return static_cast<OptionValueSInt64 *>(this);
- return NULL;
+ return nullptr;
}
const OptionValueSInt64 *
@@ -268,7 +268,7 @@ OptionValue::GetAsSInt64 () const
{
if (GetType () == OptionValue::eTypeSInt64)
return static_cast<const OptionValueSInt64 *>(this);
- return NULL;
+ return nullptr;
}
OptionValueString *
@@ -276,7 +276,7 @@ OptionValue::GetAsString ()
{
if (GetType () == OptionValue::eTypeString)
return static_cast<OptionValueString *>(this);
- return NULL;
+ return nullptr;
}
const OptionValueString *
@@ -284,7 +284,7 @@ OptionValue::GetAsString () const
{
if (GetType () == OptionValue::eTypeString)
return static_cast<const OptionValueString *>(this);
- return NULL;
+ return nullptr;
}
OptionValueUInt64 *
@@ -292,7 +292,7 @@ OptionValue::GetAsUInt64 ()
{
if (GetType () == OptionValue::eTypeUInt64)
return static_cast<OptionValueUInt64 *>(this);
- return NULL;
+ return nullptr;
}
const OptionValueUInt64 *
@@ -300,7 +300,7 @@ OptionValue::GetAsUInt64 () const
{
if (GetType () == OptionValue::eTypeUInt64)
return static_cast<const OptionValueUInt64 *>(this);
- return NULL;
+ return nullptr;
}
OptionValueUUID *
@@ -308,7 +308,7 @@ OptionValue::GetAsUUID ()
{
if (GetType () == OptionValue::eTypeUUID)
return static_cast<OptionValueUUID *>(this);
- return NULL;
+ return nullptr;
}
@@ -317,7 +317,7 @@ OptionValue::GetAsUUID () const
{
if (GetType () == OptionValue::eTypeUUID)
return static_cast<const OptionValueUUID *>(this);
- return NULL;
+ return nullptr;
}
@@ -422,7 +422,7 @@ OptionValue::GetRegexValue () const
const OptionValueRegex *option_value = GetAsRegex ();
if (option_value)
return option_value->GetCurrentValue();
- return NULL;
+ return nullptr;
}
@@ -533,7 +533,7 @@ OptionValue::GetBuiltinTypeAsCString (Type t)
case eTypeUInt64: return "unsigned";
case eTypeUUID: return "uuid";
}
- return NULL;
+ return nullptr;
}
diff --git a/source/Interpreter/OptionValueArch.cpp b/source/Interpreter/OptionValueArch.cpp
index 92fedffe75ea..6d283d6b9275 100644
--- a/source/Interpreter/OptionValueArch.cpp
+++ b/source/Interpreter/OptionValueArch.cpp
@@ -100,7 +100,7 @@ OptionValueArch::AutoComplete (CommandInterpreter &interpreter,
s,
match_start_point,
max_return_elements,
- NULL,
+ nullptr,
word_complete,
matches);
return matches.GetSize();
diff --git a/source/Interpreter/OptionValueArray.cpp b/source/Interpreter/OptionValueArray.cpp
index 9a015580bd6c..769aadd7b308 100644
--- a/source/Interpreter/OptionValueArray.cpp
+++ b/source/Interpreter/OptionValueArray.cpp
@@ -90,12 +90,12 @@ OptionValueArray::GetSubValue (const ExecutionContext *exe_ctx,
const char *end_bracket = strchr (name+1, ']');
if (end_bracket)
{
- const char *sub_value = NULL;
+ const char *sub_value = nullptr;
if (end_bracket[1])
sub_value = end_bracket + 1;
std::string index_str (name+1, end_bracket);
const size_t array_count = m_values.size();
- int32_t idx = Args::StringToSInt32(index_str.c_str(), INT32_MAX, 0, NULL);
+ int32_t idx = Args::StringToSInt32(index_str.c_str(), INT32_MAX, 0, nullptr);
if (idx != INT32_MAX)
{
;
@@ -222,7 +222,8 @@ OptionValueArray::SetArgs (const Args &args, VarSetOperationType op)
size_t i;
for (i=0; i<argc; ++i)
{
- const int idx = Args::StringToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
+ const size_t idx =
+ Args::StringToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
if (idx >= size)
{
all_indexes_valid = false;
diff --git a/source/Interpreter/OptionValueBoolean.cpp b/source/Interpreter/OptionValueBoolean.cpp
index 6471943ee5dc..bf153a1442c7 100644
--- a/source/Interpreter/OptionValueBoolean.cpp
+++ b/source/Interpreter/OptionValueBoolean.cpp
@@ -16,6 +16,7 @@
#include "lldb/Core/Stream.h"
#include "lldb/Core/StringList.h"
#include "lldb/Interpreter/Args.h"
+#include "llvm/ADT/STLExtras.h"
using namespace lldb;
using namespace lldb_private;
@@ -58,7 +59,7 @@ OptionValueBoolean::SetValueFromCString (const char *value_cstr,
}
else
{
- if (value_cstr == NULL)
+ if (value_cstr == nullptr)
error.SetErrorString ("invalid boolean string value: NULL");
else if (value_cstr[0] == '\0')
error.SetErrorString ("invalid boolean string value <empty>");
@@ -110,7 +111,7 @@ OptionValueBoolean::AutoComplete (CommandInterpreter &interpreter,
{ "1" , 1 },
{ "0" , 1 },
};
- const size_t k_num_autocomplete_entries = sizeof(g_autocomplete_entries)/sizeof(StringEntry);
+ const size_t k_num_autocomplete_entries = llvm::array_lengthof(g_autocomplete_entries);
if (s && s[0])
{
diff --git a/source/Interpreter/OptionValueDictionary.cpp b/source/Interpreter/OptionValueDictionary.cpp
index 61f8aba431ac..b560937141b3 100644
--- a/source/Interpreter/OptionValueDictionary.cpp
+++ b/source/Interpreter/OptionValueDictionary.cpp
@@ -91,7 +91,7 @@ OptionValueDictionary::GetArgs (Args &args) const
{
StreamString strm;
strm.Printf("%s=", pos->first.GetCString());
- pos->second->DumpValue(NULL, strm, eDumpOptionValue|eDumpOptionRaw);
+ pos->second->DumpValue(nullptr, strm, eDumpOptionValue|eDumpOptionRaw);
args.AppendArgument(strm.GetString().c_str());
}
return args.GetArgumentCount();
@@ -210,7 +210,7 @@ OptionValueDictionary::SetArgs (const Args &args, VarSetOperationType op)
case eVarSetOperationInsertBefore:
case eVarSetOperationInsertAfter:
case eVarSetOperationInvalid:
- error = OptionValue::SetValueFromCString (NULL, op);
+ error = OptionValue::SetValueFromCString (nullptr, op);
break;
}
return error;
@@ -230,14 +230,14 @@ OptionValueDictionary::GetSubValue (const ExecutionContext *exe_ctx, const char
if (name && name[0])
{
- const char *sub_name = NULL;
+ const char *sub_name = nullptr;
ConstString key;
const char *open_bracket = ::strchr (name, '[');
if (open_bracket)
{
const char *key_start = open_bracket + 1;
- const char *key_end = NULL;
+ const char *key_end = nullptr;
switch (open_bracket[1])
{
case '\'':
@@ -314,7 +314,7 @@ OptionValueDictionary::GetSubValue (const ExecutionContext *exe_ctx, const char
}
}
}
- if (!value_sp && error.AsCString() == NULL)
+ if (!value_sp && error.AsCString() == nullptr)
{
error.SetErrorStringWithFormat ("invalid value path '%s', %s values only support '[<key>]' subvalues where <key> a string value optionally delimitted by single or double quotes",
name,
@@ -334,7 +334,7 @@ OptionValueDictionary::SetSubValue (const ExecutionContext *exe_ctx, VarSetOpera
error = value_sp->SetValueFromCString(value, op);
else
{
- if (error.AsCString() == NULL)
+ if (error.AsCString() == nullptr)
error.SetErrorStringWithFormat("invalid value path '%s'", name);
}
return error;
@@ -361,7 +361,7 @@ OptionValueDictionary::GetStringValueForKey (const ConstString &key)
if (string_value)
return string_value->GetCurrentValue();
}
- return NULL;
+ return nullptr;
}
diff --git a/source/Interpreter/OptionValueEnumeration.cpp b/source/Interpreter/OptionValueEnumeration.cpp
index f282235d58e3..7aceac91b601 100644
--- a/source/Interpreter/OptionValueEnumeration.cpp
+++ b/source/Interpreter/OptionValueEnumeration.cpp
@@ -113,7 +113,7 @@ OptionValueEnumeration::SetEnumerations (const OptionEnumValueElement *enumerato
m_enumerations.Clear();
if (enumerators)
{
- for (size_t i=0; enumerators[i].string_value != NULL; ++i)
+ for (size_t i=0; enumerators[i].string_value != nullptr; ++i)
{
ConstString const_enumerator_name(enumerators[i].string_value);
EnumeratorInfo enumerator_info = { enumerators[i].value, enumerators[i].usage };
diff --git a/source/Interpreter/OptionValueFileSpec.cpp b/source/Interpreter/OptionValueFileSpec.cpp
index 3d2a7ff3307a..c8aaadef23bc 100644
--- a/source/Interpreter/OptionValueFileSpec.cpp
+++ b/source/Interpreter/OptionValueFileSpec.cpp
@@ -99,6 +99,7 @@ OptionValueFileSpec::SetValueFromCString (const char *value_cstr,
m_value_was_set = true;
m_current_value.SetFile(filepath.c_str(), true);
+ m_data_sp.reset();
}
else
{
@@ -139,7 +140,7 @@ OptionValueFileSpec::AutoComplete (CommandInterpreter &interpreter,
s,
match_start_point,
max_return_elements,
- NULL,
+ nullptr,
word_complete,
matches);
return matches.GetSize();
diff --git a/source/Interpreter/OptionValueFormat.cpp b/source/Interpreter/OptionValueFormat.cpp
index 34d36725fbbe..296dd983208c 100644
--- a/source/Interpreter/OptionValueFormat.cpp
+++ b/source/Interpreter/OptionValueFormat.cpp
@@ -49,7 +49,7 @@ OptionValueFormat::SetValueFromCString (const char *value_cstr, VarSetOperationT
case eVarSetOperationAssign:
{
Format new_format;
- error = Args::StringToFormat (value_cstr, new_format, NULL);
+ error = Args::StringToFormat (value_cstr, new_format, nullptr);
if (error.Success())
{
m_value_was_set = true;
diff --git a/source/Interpreter/OptionValueProperties.cpp b/source/Interpreter/OptionValueProperties.cpp
index abee55d93efa..0497ee1c15d7 100644
--- a/source/Interpreter/OptionValueProperties.cpp
+++ b/source/Interpreter/OptionValueProperties.cpp
@@ -35,6 +35,7 @@ OptionValueProperties::OptionValueProperties (const ConstString &name) :
OptionValueProperties::OptionValueProperties (const OptionValueProperties &global_properties) :
OptionValue (global_properties),
+ std::enable_shared_from_this<OptionValueProperties> (),
m_name (global_properties.m_name),
m_properties (global_properties.m_properties),
m_name_to_index (global_properties.m_name_to_index)
@@ -46,7 +47,7 @@ OptionValueProperties::OptionValueProperties (const OptionValueProperties &globa
const size_t num_properties = m_properties.size();
for (size_t i=0; i<num_properties; ++i)
{
- // Duplicate any values that are not global when contructing properties from
+ // Duplicate any values that are not global when constructing properties from
// a global copy
if (m_properties[i].IsGlobal() == false)
{
@@ -135,7 +136,7 @@ OptionValueProperties::GetSubValue (const ExecutionContext *exe_ctx,
if (name && name[0])
{
- const char *sub_name = NULL;
+ const char *sub_name = nullptr;
ConstString key;
size_t key_len = ::strcspn (name, ".[{");
@@ -163,7 +164,7 @@ OptionValueProperties::GetSubValue (const ExecutionContext *exe_ctx,
// OptionValueProperties for a lldb_private::Target might implement:
// "target.run-args{arch==i386}" -- only set run args if the arch is i386
// "target.run-args{path=/tmp/a/b/c/a.out}" -- only set run args if the path matches
- // "target.run-args{basename==test&&arch==x86_64}" -- only set run args if exectable basename is "test" and arch is "x86_64"
+ // "target.run-args{basename==test&&arch==x86_64}" -- only set run args if executable basename is "test" and arch is "x86_64"
if (sub_name[1])
{
const char *predicate_start = sub_name + 1;
@@ -218,7 +219,7 @@ OptionValueProperties::SetSubValue (const ExecutionContext *exe_ctx,
error = value_sp->SetValueFromCString(value, op);
else
{
- if (error.AsCString() == NULL)
+ if (error.AsCString() == nullptr)
error.SetErrorStringWithFormat("invalid value path '%s'", name);
}
return error;
@@ -228,7 +229,7 @@ OptionValueProperties::SetSubValue (const ExecutionContext *exe_ctx,
ConstString
OptionValueProperties::GetPropertyNameAtIndex (uint32_t idx) const
{
- const Property *property = GetPropertyAtIndex(NULL, false, idx);
+ const Property *property = GetPropertyAtIndex(nullptr, false, idx);
if (property)
return property->GetName();
return ConstString();
@@ -238,10 +239,10 @@ OptionValueProperties::GetPropertyNameAtIndex (uint32_t idx) const
const char *
OptionValueProperties::GetPropertyDescriptionAtIndex (uint32_t idx) const
{
- const Property *property = GetPropertyAtIndex(NULL, false, idx);
+ const Property *property = GetPropertyAtIndex(nullptr, false, idx);
if (property)
return property->GetDescription();
- return NULL;
+ return nullptr;
}
uint32_t
@@ -279,7 +280,7 @@ OptionValueProperties::GetPropertyAtIndexAsOptionValuePathMappings (const Execut
OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx));
if (value_sp)
return value_sp->GetAsPathMappings();
- return NULL;
+ return nullptr;
}
OptionValueFileSpecList *
@@ -288,7 +289,7 @@ OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpecList (const Execut
OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx));
if (value_sp)
return value_sp->GetAsFileSpecList();
- return NULL;
+ return nullptr;
}
OptionValueArch *
@@ -297,7 +298,7 @@ OptionValueProperties::GetPropertyAtIndexAsOptionValueArch (const ExecutionConte
const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
if (property)
return property->GetValue()->GetAsArch();
- return NULL;
+ return nullptr;
}
bool
@@ -381,7 +382,7 @@ OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary (const Executio
const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
if (property)
return property->GetValue()->GetAsDictionary();
- return NULL;
+ return nullptr;
}
int64_t
@@ -421,7 +422,7 @@ OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpec (const ExecutionC
if (value)
return value->GetAsFileSpec();
}
- return NULL;
+ return nullptr;
}
@@ -462,7 +463,7 @@ OptionValueProperties::GetPropertyAtIndexAsOptionValueRegex (const ExecutionCont
if (value)
return value->GetRegexValue();
}
- return NULL;
+ return nullptr;
}
OptionValueSInt64 *
@@ -475,7 +476,7 @@ OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64 (const ExecutionCon
if (value)
return value->GetAsSInt64();
}
- return NULL;
+ return nullptr;
}
int64_t
@@ -536,7 +537,7 @@ OptionValueProperties::GetPropertyAtIndexAsOptionValueString (const ExecutionCon
OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx));
if (value_sp)
return value_sp->GetAsString();
- return NULL;
+ return nullptr;
}
@@ -659,10 +660,10 @@ OptionValueProperties::GetPropertyAtPath (const ExecutionContext *exe_ctx,
bool will_modify,
const char *name) const
{
- const Property *property = NULL;
+ const Property *property = nullptr;
if (name && name[0])
{
- const char *sub_name = NULL;
+ const char *sub_name = nullptr;
ConstString key;
size_t key_len = ::strcspn (name, ".[{");
@@ -683,7 +684,7 @@ OptionValueProperties::GetPropertyAtPath (const ExecutionContext *exe_ctx,
if (sub_properties)
return sub_properties->GetPropertyAtPath(exe_ctx, will_modify, sub_name + 1);
}
- property = NULL;
+ property = nullptr;
}
}
return property;
diff --git a/source/Interpreter/OptionValueUUID.cpp b/source/Interpreter/OptionValueUUID.cpp
index 340f1e5e9986..0141911d97ad 100644
--- a/source/Interpreter/OptionValueUUID.cpp
+++ b/source/Interpreter/OptionValueUUID.cpp
@@ -92,7 +92,7 @@ OptionValueUUID::AutoComplete (CommandInterpreter &interpreter,
if (num_modules > 0)
{
UUID::ValueType uuid_bytes;
- const size_t num_bytes_decoded = UUID::DecodeUUIDBytesFromCString(s, uuid_bytes, NULL);
+ const size_t num_bytes_decoded = UUID::DecodeUUIDBytesFromCString(s, uuid_bytes, nullptr);
for (size_t i=0; i<num_modules; ++i)
{
ModuleSP module_sp (target->GetImages().GetModuleAtIndex(i));
diff --git a/source/Interpreter/Options.cpp b/source/Interpreter/Options.cpp
index c6c66d8ac650..a8766f5f8615 100644
--- a/source/Interpreter/Options.cpp
+++ b/source/Interpreter/Options.cpp
@@ -242,14 +242,14 @@ uint32_t
Options::NumCommandOptions ()
{
const OptionDefinition *opt_defs = GetDefinitions ();
- if (opt_defs == NULL)
+ if (opt_defs == nullptr)
return 0;
int i = 0;
- if (opt_defs != NULL)
+ if (opt_defs != nullptr)
{
- while (opt_defs[i].long_option != NULL)
+ while (opt_defs[i].long_option != nullptr)
++i;
}
@@ -265,7 +265,7 @@ Options::GetLongOptions ()
// Check to see if there are any options.
const uint32_t num_options = NumCommandOptions();
if (num_options == 0)
- return NULL;
+ return nullptr;
uint32_t i;
const OptionDefinition *opt_defs = GetDefinitions();
@@ -277,9 +277,8 @@ Options::GetLongOptions ()
{
const int short_opt = opt_defs[i].short_option;
- m_getopt_table[i].name = opt_defs[i].long_option;
- m_getopt_table[i].has_arg = opt_defs[i].option_has_arg;
- m_getopt_table[i].flag = NULL;
+ m_getopt_table[i].definition = &opt_defs[i];
+ m_getopt_table[i].flag = nullptr;
m_getopt_table[i].val = short_opt;
if (option_seen.find(short_opt) == option_seen.end())
@@ -297,7 +296,7 @@ Options::GetLongOptions ()
opt_defs[i].long_option,
short_opt,
pos->second,
- m_getopt_table[pos->second].name,
+ m_getopt_table[pos->second].definition->long_option,
opt_defs[i].long_option);
else
Host::SystemLog (Host::eSystemLogError, "option[%u] --%s has a short option 0x%x that conflicts with option[%u] --%s, short option won't be used for --%s\n",
@@ -305,21 +304,20 @@ Options::GetLongOptions ()
opt_defs[i].long_option,
short_opt,
pos->second,
- m_getopt_table[pos->second].name,
+ m_getopt_table[pos->second].definition->long_option,
opt_defs[i].long_option);
}
}
//getopt_long_only requires a NULL final entry in the table:
- m_getopt_table[i].name = NULL;
- m_getopt_table[i].has_arg = 0;
- m_getopt_table[i].flag = NULL;
- m_getopt_table[i].val = 0;
+ m_getopt_table[i].definition = nullptr;
+ m_getopt_table[i].flag = nullptr;
+ m_getopt_table[i].val = 0;
}
if (m_getopt_table.empty())
- return NULL;
+ return nullptr;
return &m_getopt_table.front();
}
@@ -336,18 +334,29 @@ void
Options::OutputFormattedUsageText
(
Stream &strm,
- const char *text,
+ const OptionDefinition &option_def,
uint32_t output_max_columns
)
{
- int len = strlen (text);
+ std::string actual_text;
+ if (option_def.validator)
+ {
+ const char *condition = option_def.validator->ShortConditionString();
+ if (condition)
+ {
+ actual_text = "[";
+ actual_text.append(condition);
+ actual_text.append("] ");
+ }
+ }
+ actual_text.append(option_def.usage_text);
// Will it all fit on one line?
- if ((len + strm.GetIndentLevel()) < output_max_columns)
+ if (static_cast<uint32_t>(actual_text.length() + strm.GetIndentLevel()) < output_max_columns)
{
// Output it as a single line.
- strm.Indent (text);
+ strm.Indent (actual_text.c_str());
strm.EOL();
}
else
@@ -357,13 +366,13 @@ Options::OutputFormattedUsageText
int text_width = output_max_columns - strm.GetIndentLevel() - 1;
int start = 0;
int end = start;
- int final_end = strlen (text);
+ int final_end = actual_text.length();
int sub_len;
while (end < final_end)
{
// Don't start the 'text' on a space, since we're already outputting the indentation.
- while ((start < final_end) && (text[start] == ' '))
+ while ((start < final_end) && (actual_text[start] == ' '))
start++;
end = start + text_width;
@@ -373,7 +382,7 @@ Options::OutputFormattedUsageText
{
// If we're not at the end of the text, make sure we break the line on white space.
while (end > start
- && text[end] != ' ' && text[end] != '\t' && text[end] != '\n')
+ && actual_text[end] != ' ' && actual_text[end] != '\t' && actual_text[end] != '\n')
end--;
}
@@ -383,7 +392,7 @@ Options::OutputFormattedUsageText
strm.Indent();
assert (start < final_end);
assert (start + sub_len <= final_end);
- strm.Write(text + start, sub_len);
+ strm.Write(actual_text.c_str() + start, sub_len);
start = end + 1;
}
strm.EOL();
@@ -592,7 +601,7 @@ Options::GenerateOptionUsage
if (opt_defs[i].usage_mask & opt_set_mask && isprint8(opt_defs[i].short_option))
{
if (opt_defs[i].required && opt_defs[i].option_has_arg != OptionParser::eNoArgument)
- PrintOption (opt_defs[i], eDisplayBestOption, " ", NULL, true, strm);
+ PrintOption (opt_defs[i], eDisplayBestOption, " ", nullptr, true, strm);
}
}
@@ -605,7 +614,7 @@ Options::GenerateOptionUsage
// Add current option to the end of out_stream.
if (!opt_defs[i].required && opt_defs[i].option_has_arg != OptionParser::eNoArgument)
- PrintOption (opt_defs[i], eDisplayBestOption, " ", NULL, true, strm);
+ PrintOption (opt_defs[i], eDisplayBestOption, " ", nullptr, true, strm);
}
}
@@ -630,7 +639,7 @@ Options::GenerateOptionUsage
strm.Printf ("\n\n");
// Now print out all the detailed information about the various options: long form, short form and help text:
- // --long_name <argument> ( -short <argument> )
+ // -short <argument> ( --long_name <argument> )
// help text
// This variable is used to keep track of which options' info we've printed out, because some options can be in
@@ -669,13 +678,13 @@ Options::GenerateOptionUsage
strm.Indent ();
if (opt_defs[i].short_option && isprint8(opt_defs[i].short_option))
{
- PrintOption (opt_defs[i], eDisplayShortOption, NULL, NULL, false, strm);
+ PrintOption (opt_defs[i], eDisplayShortOption, nullptr, nullptr, false, strm);
PrintOption (opt_defs[i], eDisplayLongOption, " ( ", " )", false, strm);
}
else
{
// Short option is not printable, just print long option
- PrintOption (opt_defs[i], eDisplayLongOption, NULL, NULL, false, strm);
+ PrintOption (opt_defs[i], eDisplayLongOption, nullptr, nullptr, false, strm);
}
strm.EOL();
@@ -683,13 +692,13 @@ Options::GenerateOptionUsage
if (opt_defs[i].usage_text)
OutputFormattedUsageText (strm,
- opt_defs[i].usage_text,
+ opt_defs[i],
screen_width);
- if (opt_defs[i].enum_values != NULL)
+ if (opt_defs[i].enum_values != nullptr)
{
strm.Indent ();
strm.Printf("Values: ");
- for (int k = 0; opt_defs[i].enum_values[k].string_value != NULL; k++)
+ for (int k = 0; opt_defs[i].enum_values[k].string_value != nullptr; k++)
{
if (k == 0)
strm.Printf("%s", opt_defs[i].enum_values[k].string_value);
@@ -908,11 +917,11 @@ Options::HandleOptionArgumentCompletion
// See if this is an enumeration type option, and if so complete it here:
OptionEnumValueElement *enum_values = opt_defs[opt_defs_index].enum_values;
- if (enum_values != NULL)
+ if (enum_values != nullptr)
{
bool return_value = false;
std::string match_string(input.GetArgumentAtIndex (opt_arg_pos), input.GetArgumentAtIndex (opt_arg_pos) + char_pos);
- for (int i = 0; enum_values[i].string_value != NULL; i++)
+ for (int i = 0; enum_values[i].string_value != nullptr; i++)
{
if (strstr(enum_values[i].string_value, match_string.c_str()) == enum_values[i].string_value)
{
@@ -1001,7 +1010,7 @@ OptionGroupOptions::GetGroupWithOption (char short_opt)
if (opt_def.short_option == short_opt)
return m_option_infos[i].option_group;
}
- return NULL;
+ return nullptr;
}
void
@@ -1026,7 +1035,7 @@ void
OptionGroupOptions::Finalize ()
{
m_did_finalize = true;
- OptionDefinition empty_option_def = { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL };
+ OptionDefinition empty_option_def = { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr };
m_option_defs.push_back (empty_option_def);
}
diff --git a/source/Interpreter/Property.cpp b/source/Interpreter/Property.cpp
index e5cf63ada882..49376266b077 100644
--- a/source/Interpreter/Property.cpp
+++ b/source/Interpreter/Property.cpp
@@ -56,7 +56,7 @@ Property::Property (const PropertyDefinition &definition) :
// "definition.default_cstr_value" as a string value that represents the default
// value.
if (definition.default_cstr_value)
- m_value_sp.reset (new OptionValueBoolean(Args::StringToBoolean (definition.default_cstr_value, false, NULL)));
+ m_value_sp.reset (new OptionValueBoolean(Args::StringToBoolean (definition.default_cstr_value, false, nullptr)));
else
m_value_sp.reset (new OptionValueBoolean(definition.default_uint_value != 0));
break;
@@ -108,7 +108,7 @@ Property::Property (const PropertyDefinition &definition) :
{
Format new_format = eFormatInvalid;
if (definition.default_cstr_value)
- Args::StringToFormat (definition.default_cstr_value, new_format, NULL);
+ Args::StringToFormat (definition.default_cstr_value, new_format, nullptr);
else
new_format = (Format)definition.default_uint_value;
m_value_sp.reset (new OptionValueFormat(new_format));
diff --git a/source/Interpreter/PythonDataObjects.cpp b/source/Interpreter/PythonDataObjects.cpp
index 053ff34b9d77..3ea6c0dbe3e5 100644
--- a/source/Interpreter/PythonDataObjects.cpp
+++ b/source/Interpreter/PythonDataObjects.cpp
@@ -31,7 +31,7 @@ using namespace lldb;
// PythonObject
//----------------------------------------------------------------------
PythonObject::PythonObject (const lldb::ScriptInterpreterObjectSP &script_object_sp) :
- m_py_obj (NULL)
+ m_py_obj (nullptr)
{
if (script_object_sp)
Reset ((PyObject *)script_object_sp->GetObject());
@@ -133,8 +133,8 @@ PythonString::Reset (PyObject *py_obj)
if (py_obj && PyString_Check(py_obj))
return PythonObject::Reset(py_obj);
- PythonObject::Reset(NULL);
- return py_obj == NULL;
+ PythonObject::Reset(nullptr);
+ return py_obj == nullptr;
}
const char*
@@ -142,7 +142,7 @@ PythonString::GetString() const
{
if (m_py_obj)
return PyString_AsString(m_py_obj);
- return NULL;
+ return nullptr;
}
size_t
@@ -202,8 +202,8 @@ PythonInteger::Reset (PyObject *py_obj)
return PythonObject::Reset(py_obj);
}
- PythonObject::Reset(NULL);
- return py_obj == NULL;
+ PythonObject::Reset(nullptr);
+ return py_obj == nullptr;
}
int64_t
@@ -230,7 +230,7 @@ PythonInteger::SetInteger (int64_t value)
//----------------------------------------------------------------------
PythonList::PythonList (bool create_empty) :
- PythonObject(create_empty ? PyList_New(0) : NULL)
+ PythonObject(create_empty ? PyList_New(0) : nullptr)
{
}
@@ -269,8 +269,8 @@ PythonList::Reset (PyObject *py_obj)
if (py_obj && PyList_Check(py_obj))
return PythonObject::Reset(py_obj);
- PythonObject::Reset(NULL);
- return py_obj == NULL;
+ PythonObject::Reset(nullptr);
+ return py_obj == nullptr;
}
uint32_t
@@ -308,7 +308,7 @@ PythonList::AppendItem (const PythonObject &object)
//----------------------------------------------------------------------
PythonDictionary::PythonDictionary (bool create_empty) :
-PythonObject(create_empty ? PyDict_New() : NULL)
+PythonObject(create_empty ? PyDict_New() : nullptr)
{
}
@@ -342,8 +342,8 @@ PythonDictionary::Reset (PyObject *py_obj)
if (py_obj && PyDict_Check(py_obj))
return PythonObject::Reset(py_obj);
- PythonObject::Reset(NULL);
- return py_obj == NULL;
+ PythonObject::Reset(nullptr);
+ return py_obj == nullptr;
}
uint32_t
diff --git a/source/Interpreter/ScriptInterpreter.cpp b/source/Interpreter/ScriptInterpreter.cpp
index 1b751afb135e..b6c46f83bd92 100644
--- a/source/Interpreter/ScriptInterpreter.cpp
+++ b/source/Interpreter/ScriptInterpreter.cpp
@@ -44,7 +44,7 @@ ScriptInterpreter::GetCommandInterpreter ()
void
ScriptInterpreter::CollectDataForBreakpointCommandCallback
(
- BreakpointOptions *bp_options,
+ std::vector<BreakpointOptions *> &bp_options_vec,
CommandReturnObject &result
)
{
@@ -81,6 +81,30 @@ ScriptInterpreter::LanguageToString (lldb::ScriptLanguage language)
return return_value;
}
+Error
+ScriptInterpreter::SetBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec,
+ const char *callback_text)
+{
+ Error return_error;
+ for (BreakpointOptions *bp_options : bp_options_vec)
+ {
+ return_error = SetBreakpointCommandCallback(bp_options, callback_text);
+ if (return_error.Success())
+ break;
+ }
+ return return_error;
+}
+
+void
+ScriptInterpreter::SetBreakpointCommandCallbackFunction (std::vector<BreakpointOptions *> &bp_options_vec,
+ const char *function_name)
+{
+ for (BreakpointOptions *bp_options : bp_options_vec)
+ {
+ SetBreakpointCommandCallbackFunction(bp_options, function_name);
+ }
+}
+
std::unique_ptr<ScriptInterpreterLocker>
ScriptInterpreter::AcquireInterpreterLock ()
{
@@ -132,12 +156,3 @@ ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_call
swig_plugin_get);
#endif // #ifndef LLDB_DISABLE_PYTHON
}
-
-void
-ScriptInterpreter::TerminateInterpreter ()
-{
-#ifndef LLDB_DISABLE_PYTHON
- ScriptInterpreterPython::TerminateInterpreter ();
-#endif // #ifndef LLDB_DISABLE_PYTHON
-}
-
diff --git a/source/Interpreter/ScriptInterpreterPython.cpp b/source/Interpreter/ScriptInterpreterPython.cpp
index c1d28e88afc1..1b24fea7c218 100644
--- a/source/Interpreter/ScriptInterpreterPython.cpp
+++ b/source/Interpreter/ScriptInterpreterPython.cpp
@@ -31,7 +31,8 @@
#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Timer.h"
-#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/Pipe.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/PythonDataObjects.h"
@@ -41,33 +42,26 @@ using namespace lldb;
using namespace lldb_private;
-static ScriptInterpreter::SWIGInitCallback g_swig_init_callback = NULL;
-static ScriptInterpreter::SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = NULL;
-static ScriptInterpreter::SWIGWatchpointCallbackFunction g_swig_watchpoint_callback = NULL;
-static ScriptInterpreter::SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = NULL;
-static ScriptInterpreter::SWIGPythonCreateSyntheticProvider g_swig_synthetic_script = NULL;
-static ScriptInterpreter::SWIGPythonCalculateNumChildren g_swig_calc_children = NULL;
-static ScriptInterpreter::SWIGPythonGetChildAtIndex g_swig_get_child_index = NULL;
-static ScriptInterpreter::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = NULL;
-static ScriptInterpreter::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue = NULL;
-static ScriptInterpreter::SWIGPythonGetValueObjectSPFromSBValue g_swig_get_valobj_sp_from_sbvalue = NULL;
-static ScriptInterpreter::SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = NULL;
-static ScriptInterpreter::SWIGPythonMightHaveChildrenSynthProviderInstance g_swig_mighthavechildren_provider = NULL;
-static ScriptInterpreter::SWIGPythonCallCommand g_swig_call_command = NULL;
-static ScriptInterpreter::SWIGPythonCallModuleInit g_swig_call_module_init = NULL;
-static ScriptInterpreter::SWIGPythonCreateOSPlugin g_swig_create_os_plugin = NULL;
-static ScriptInterpreter::SWIGPythonScriptKeyword_Process g_swig_run_script_keyword_process = NULL;
-static ScriptInterpreter::SWIGPythonScriptKeyword_Thread g_swig_run_script_keyword_thread = NULL;
-static ScriptInterpreter::SWIGPythonScriptKeyword_Target g_swig_run_script_keyword_target = NULL;
-static ScriptInterpreter::SWIGPythonScriptKeyword_Frame g_swig_run_script_keyword_frame = NULL;
-static ScriptInterpreter::SWIGPython_GetDynamicSetting g_swig_plugin_get = NULL;
-
-static int
-_check_and_flush (FILE *stream)
-{
- int prev_fail = ferror (stream);
- return fflush (stream) || prev_fail ? EOF : 0;
-}
+static ScriptInterpreter::SWIGInitCallback g_swig_init_callback = nullptr;
+static ScriptInterpreter::SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = nullptr;
+static ScriptInterpreter::SWIGWatchpointCallbackFunction g_swig_watchpoint_callback = nullptr;
+static ScriptInterpreter::SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = nullptr;
+static ScriptInterpreter::SWIGPythonCreateSyntheticProvider g_swig_synthetic_script = nullptr;
+static ScriptInterpreter::SWIGPythonCalculateNumChildren g_swig_calc_children = nullptr;
+static ScriptInterpreter::SWIGPythonGetChildAtIndex g_swig_get_child_index = nullptr;
+static ScriptInterpreter::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = nullptr;
+static ScriptInterpreter::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue = nullptr;
+static ScriptInterpreter::SWIGPythonGetValueObjectSPFromSBValue g_swig_get_valobj_sp_from_sbvalue = nullptr;
+static ScriptInterpreter::SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = nullptr;
+static ScriptInterpreter::SWIGPythonMightHaveChildrenSynthProviderInstance g_swig_mighthavechildren_provider = nullptr;
+static ScriptInterpreter::SWIGPythonCallCommand g_swig_call_command = nullptr;
+static ScriptInterpreter::SWIGPythonCallModuleInit g_swig_call_module_init = nullptr;
+static ScriptInterpreter::SWIGPythonCreateOSPlugin g_swig_create_os_plugin = nullptr;
+static ScriptInterpreter::SWIGPythonScriptKeyword_Process g_swig_run_script_keyword_process = nullptr;
+static ScriptInterpreter::SWIGPythonScriptKeyword_Thread g_swig_run_script_keyword_thread = nullptr;
+static ScriptInterpreter::SWIGPythonScriptKeyword_Target g_swig_run_script_keyword_target = nullptr;
+static ScriptInterpreter::SWIGPythonScriptKeyword_Frame g_swig_run_script_keyword_frame = nullptr;
+static ScriptInterpreter::SWIGPython_GetDynamicSetting g_swig_plugin_get = nullptr;
static std::string
ReadPythonBacktrace (PyObject* py_backtrace);
@@ -100,6 +94,13 @@ ScriptInterpreterPython::Locker::DoAcquireLock()
m_GILState = PyGILState_Ensure();
if (log)
log->Printf("Ensured PyGILState. Previous state = %slocked\n", m_GILState == PyGILState_UNLOCKED ? "un" : "");
+
+ // we need to save the thread state when we first start the command
+ // because we might decide to interrupt it while some action is taking
+ // place outside of Python (e.g. printing to screen, waiting for the network, ...)
+ // in that case, _PyThreadState_Current will be NULL - and we would be unable
+ // to set the asynchronous exception - not a desirable situation
+ m_python_interpreter->SetThreadState (_PyThreadState_Current);
return true;
}
@@ -156,7 +157,7 @@ ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interprete
m_session_is_active (false),
m_pty_slave_is_open (false),
m_valid_session (true),
- m_command_thread_state (NULL)
+ m_command_thread_state (nullptr)
{
ScriptInterpreterPython::InitializePrivate ();
@@ -213,7 +214,7 @@ ScriptInterpreterPython::~ScriptInterpreterPython ()
void
ScriptInterpreterPython::IOHandlerActivated (IOHandler &io_handler)
{
- const char *instructions = NULL;
+ const char *instructions = nullptr;
switch (m_active_io_handler)
{
@@ -255,24 +256,30 @@ ScriptInterpreterPython::IOHandlerInputComplete (IOHandler &io_handler, std::str
break;
case eIOHandlerBreakpoint:
{
- BreakpointOptions *bp_options = (BreakpointOptions *)io_handler.GetUserData();
- std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
- if (data_ap.get())
+ std::vector<BreakpointOptions *> *bp_options_vec = (std::vector<BreakpointOptions *> *)io_handler.GetUserData();
+ for (auto bp_options : *bp_options_vec)
{
- data_ap->user_source.SplitIntoLines(data);
-
- if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source))
+ if (!bp_options)
+ continue;
+
+ std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
+ if (data_ap.get())
{
- BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
- bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp);
- }
- else if (!batch_mode)
- {
- StreamFileSP error_sp = io_handler.GetErrorStreamFile();
- if (error_sp)
+ data_ap->user_source.SplitIntoLines(data);
+
+ if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source).Success())
{
- error_sp->Printf ("Warning: No command attached to breakpoint.\n");
- error_sp->Flush();
+ BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
+ bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp);
+ }
+ else if (!batch_mode)
+ {
+ StreamFileSP error_sp = io_handler.GetErrorStreamFile();
+ if (error_sp)
+ {
+ error_sp->Printf ("Warning: No command attached to breakpoint.\n");
+ error_sp->Flush();
+ }
}
}
}
@@ -306,8 +313,6 @@ ScriptInterpreterPython::IOHandlerInputComplete (IOHandler &io_handler, std::str
}
break;
}
-
-
}
@@ -427,42 +432,42 @@ ScriptInterpreterPython::EnterSession (uint16_t on_entry_flags,
lldb::StreamFileSP in_sp;
lldb::StreamFileSP out_sp;
lldb::StreamFileSP err_sp;
- if (in == NULL || out == NULL || err == NULL)
+ if (in == nullptr || out == nullptr || err == nullptr)
m_interpreter.GetDebugger().AdoptTopIOHandlerFilesIfInvalid (in_sp, out_sp, err_sp);
- if (in == NULL && in_sp && (on_entry_flags & Locker::NoSTDIN) == 0)
+ if (in == nullptr && in_sp && (on_entry_flags & Locker::NoSTDIN) == 0)
in = in_sp->GetFile().GetStream();
if (in)
{
m_saved_stdin.Reset(sys_module_dict.GetItemForKey("stdin"));
- PyObject *new_file = PyFile_FromFile (in, (char *) "", (char *) "r", 0);
+ PyObject *new_file = PyFile_FromFile (in, (char *) "", (char *) "r", nullptr);
sys_module_dict.SetItemForKey ("stdin", new_file);
Py_DECREF (new_file);
}
else
m_saved_stdin.Reset();
- if (out == NULL && out_sp)
+ if (out == nullptr && out_sp)
out = out_sp->GetFile().GetStream();
if (out)
{
m_saved_stdout.Reset(sys_module_dict.GetItemForKey("stdout"));
- PyObject *new_file = PyFile_FromFile (out, (char *) "", (char *) "w", 0);
+ PyObject *new_file = PyFile_FromFile (out, (char *) "", (char *) "w", nullptr);
sys_module_dict.SetItemForKey ("stdout", new_file);
Py_DECREF (new_file);
}
else
m_saved_stdout.Reset();
- if (err == NULL && err_sp)
+ if (err == nullptr && err_sp)
err = err_sp->GetFile().GetStream();
if (err)
{
m_saved_stderr.Reset(sys_module_dict.GetItemForKey("stderr"));
- PyObject *new_file = PyFile_FromFile (err, (char *) "", (char *) "w", 0);
+ PyObject *new_file = PyFile_FromFile (err, (char *) "", (char *) "w", nullptr);
sys_module_dict.SetItemForKey ("stderr", new_file);
Py_DECREF (new_file);
}
@@ -517,7 +522,7 @@ ScriptInterpreterPython::GetSysModuleDictionary ()
static std::string
GenerateUniqueName (const char* base_name_wanted,
uint32_t& functions_counter,
- void* name_token = NULL)
+ void* name_token = nullptr)
{
StreamString sstr;
@@ -538,7 +543,7 @@ ScriptInterpreterPython::GetEmbeddedInterpreterModuleObjects ()
if (!m_run_one_line_function)
{
PyObject *module = PyImport_AddModule ("lldb.embedded_interpreter");
- if (module != NULL)
+ if (module != nullptr)
{
PythonDictionary module_dict (PyModule_GetDict (module));
if (module_dict)
@@ -580,8 +585,7 @@ ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObjec
StreamFileSP output_file_sp;
StreamFileSP error_file_sp;
Communication output_comm ("lldb.ScriptInterpreterPython.ExecuteOneLine.comm");
- int pipe_fds[2] = { -1, -1 };
-
+ bool join_read_thread = false;
if (options.GetEnableIO())
{
if (result)
@@ -589,20 +593,21 @@ ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObjec
input_file_sp = debugger.GetInputFile();
// Set output to a temporary file so we can forward the results on to the result object
- int err = pipe(pipe_fds);
- if (err == 0)
+ Pipe pipe;
+ if (pipe.Open())
{
- std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor(pipe_fds[0], true));
+ std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor(pipe.ReleaseReadFileDescriptor(), true));
if (conn_ap->IsConnected())
{
output_comm.SetConnection(conn_ap.release());
output_comm.SetReadThreadBytesReceivedCallback(ReadThreadBytesReceived, &result->GetOutputStream());
output_comm.StartReadThread();
- FILE *outfile_handle = fdopen (pipe_fds[1], "w");
+ join_read_thread = true;
+ FILE *outfile_handle = fdopen (pipe.ReleaseWriteFileDescriptor(), "w");
output_file_sp.reset(new StreamFile(outfile_handle, true));
error_file_sp = output_file_sp;
if (outfile_handle)
- ::setbuf (outfile_handle, NULL);
+ ::setbuf (outfile_handle, nullptr);
result->SetImmediateOutputFile(debugger.GetOutputFile()->GetFile().GetStream());
result->SetImmediateErrorFile(debugger.GetErrorFile()->GetFile().GetStream());
@@ -667,7 +672,7 @@ ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObjec
if (out_file != err_file)
::fflush (err_file);
- if (pipe_fds[0] != -1)
+ if (join_read_thread)
{
// Close the write end of the pipe since we are done with our
// one line script. This should cause the read thread that
@@ -788,10 +793,27 @@ public:
}
- virtual void
+ virtual bool
Interrupt ()
{
-
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT));
+
+ PyThreadState* state = _PyThreadState_Current;
+ if (!state)
+ state = m_python->GetThreadState();
+ if (state)
+ {
+ long tid = state->thread_id;
+ _PyThreadState_Current = state;
+ int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt);
+ if (log)
+ log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, tid = %ld, num_threads = %d, state = %p",
+ tid, num_threads, static_cast<void *>(state));
+ }
+ else if (log)
+ log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, state = NULL");
+
+ return false;
}
virtual void
@@ -834,13 +856,13 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string,
{
Locker locker(this,
- ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0),
+ ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0) | Locker::NoSTDIN,
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
- PyObject *py_return = NULL;
+ PyObject *py_return = nullptr;
PythonObject &main_module = GetMainModule ();
PythonDictionary globals (PyModule_GetDict(main_module.get()));
- PyObject *py_error = NULL;
+ PyObject *py_error = nullptr;
bool ret_success = false;
int success;
@@ -855,25 +877,25 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string,
locals = globals;
py_error = PyErr_Occurred();
- if (py_error != NULL)
+ if (py_error != nullptr)
PyErr_Clear();
- if (in_string != NULL)
+ if (in_string != nullptr)
{
{ // scope for PythonInputReaderManager
//PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL);
py_return = PyRun_String (in_string, Py_eval_input, globals.get(), locals.get());
- if (py_return == NULL)
+ if (py_return == nullptr)
{
py_error = PyErr_Occurred ();
- if (py_error != NULL)
+ if (py_error != nullptr)
PyErr_Clear ();
py_return = PyRun_String (in_string, Py_single_input, globals.get(), locals.get());
}
}
- if (py_return != NULL)
+ if (py_return != nullptr)
{
switch (return_type)
{
@@ -978,7 +1000,7 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string,
}
py_error = PyErr_Occurred();
- if (py_error != NULL)
+ if (py_error != nullptr)
{
ret_success = false;
if (options.GetMaskoutErrors())
@@ -998,14 +1020,13 @@ ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const Exec
Error error;
Locker locker(this,
- ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0),
+ ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0) | Locker::NoSTDIN,
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
- bool success = false;
PythonObject return_value;
PythonObject &main_module = GetMainModule ();
PythonDictionary globals (PyModule_GetDict(main_module.get()));
- PyObject *py_error = NULL;
+ PyObject *py_error = nullptr;
PythonDictionary locals = GetSessionDictionary ();
@@ -1020,10 +1041,10 @@ ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const Exec
}
py_error = PyErr_Occurred();
- if (py_error != NULL)
+ if (py_error != nullptr)
PyErr_Clear();
- if (in_string != NULL)
+ if (in_string != nullptr)
{
struct _node *compiled_node = PyParser_SimpleParseString (in_string, Py_file_input);
if (compiled_node)
@@ -1031,27 +1052,22 @@ ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const Exec
PyCodeObject *compiled_code = PyNode_Compile (compiled_node, "temp.py");
if (compiled_code)
{
- { // scope for PythonInputReaderManager
- //PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL);
- return_value.Reset(PyEval_EvalCode (compiled_code, globals.get(), locals.get()));
- }
- if (return_value)
- success = true;
+ return_value.Reset(PyEval_EvalCode (compiled_code, globals.get(), locals.get()));
}
}
}
py_error = PyErr_Occurred ();
- if (py_error != NULL)
+ if (py_error != nullptr)
{
// puts(in_string);
// _PyObject_Dump (py_error);
// PyErr_Print();
// success = false;
- PyObject *type = NULL;
- PyObject *value = NULL;
- PyObject *traceback = NULL;
+ PyObject *type = nullptr;
+ PyObject *value = nullptr;
+ PyObject *traceback = nullptr;
PyErr_Fetch (&type,&value,&traceback);
// get the backtrace
@@ -1075,11 +1091,11 @@ ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const Exec
void
-ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec,
CommandReturnObject &result)
{
m_active_io_handler = eIOHandlerBreakpoint;
- m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, bp_options);
+ m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, &bp_options_vec);
}
void
@@ -1090,27 +1106,39 @@ ScriptInterpreterPython::CollectDataForWatchpointCommandCallback (WatchpointOpti
m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, wp_options);
}
-// Set a Python one-liner as the callback for the breakpoint.
void
+ScriptInterpreterPython::SetBreakpointCommandCallbackFunction (BreakpointOptions *bp_options,
+ const char *function_name)
+{
+ // For now just cons up a oneliner that calls the provided function.
+ std::string oneliner("return ");
+ oneliner += function_name;
+ oneliner += "(frame, bp_loc, internal_dict)";
+ m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
+ oneliner.c_str());
+}
+
+// Set a Python one-liner as the callback for the breakpoint.
+Error
ScriptInterpreterPython::SetBreakpointCommandCallback (BreakpointOptions *bp_options,
- const char *oneliner)
+ const char *command_body_text)
{
std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
- // It's necessary to set both user_source and script_source to the oneliner.
- // The former is used to generate callback description (as in breakpoint command list)
- // while the latter is used for Python to interpret during the actual callback.
-
- data_ap->user_source.AppendString (oneliner);
- data_ap->script_source.assign (oneliner);
-
- if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source))
+ // Split the command_body_text into lines, and pass that to GenerateBreakpointCommandCallbackData. That will
+ // wrap the body in an auto-generated function, and return the function name in script_source. That is what
+ // the callback will actually invoke.
+
+ data_ap->user_source.SplitIntoLines(command_body_text);
+ Error error = GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source);
+ if (error.Success())
{
BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp);
+ return error;
}
-
- return;
+ else
+ return error;
}
// Set a Python one-liner as the callback for the watchpoint.
@@ -1136,24 +1164,32 @@ ScriptInterpreterPython::SetWatchpointCommandCallback (WatchpointOptions *wp_opt
return;
}
-bool
+Error
ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter (StringList &function_def)
{
// Convert StringList to one long, newline delimited, const char *.
std::string function_def_string(function_def.CopyList());
- return ExecuteMultipleLines (function_def_string.c_str(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false)).Success();
+ Error error = ExecuteMultipleLines (function_def_string.c_str(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false));
+ return error;
}
-bool
+Error
ScriptInterpreterPython::GenerateFunction(const char *signature, const StringList &input)
{
+ Error error;
int num_lines = input.GetSize ();
if (num_lines == 0)
- return false;
+ {
+ error.SetErrorString ("No input data.");
+ return error;
+ }
if (!signature || *signature == 0)
- return false;
+ {
+ error.SetErrorString("No output function name.");
+ return error;
+ }
StreamString sstr;
StringList auto_generated_function;
@@ -1180,11 +1216,9 @@ ScriptInterpreterPython::GenerateFunction(const char *signature, const StringLis
// Verify that the results are valid Python.
- if (!ExportFunctionDefinitionToInterpreter (auto_generated_function))
- return false;
+ error = ExportFunctionDefinitionToInterpreter (auto_generated_function);
- return true;
-
+ return error;
}
bool
@@ -1204,7 +1238,7 @@ ScriptInterpreterPython::GenerateTypeScriptFunction (StringList &user_input, std
std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_type_print_func", num_created_functions, name_token));
sstr.Printf ("def %s (valobj, internal_dict):", auto_generated_function_name.c_str());
- if (!GenerateFunction(sstr.GetData(), user_input))
+ if (!GenerateFunction(sstr.GetData(), user_input).Success())
return false;
// Store the name of the auto-generated function to be called.
@@ -1227,7 +1261,7 @@ ScriptInterpreterPython::GenerateScriptAliasFunction (StringList &user_input, st
sstr.Printf ("def %s (debugger, args, result, internal_dict):", auto_generated_function_name.c_str());
- if (!GenerateFunction(sstr.GetData(),user_input))
+ if (!GenerateFunction(sstr.GetData(),user_input).Success())
return false;
// Store the name of the auto-generated function to be called.
@@ -1273,7 +1307,7 @@ ScriptInterpreterPython::GenerateTypeSynthClass (StringList &user_input, std::st
// Verify that the results are valid Python.
// (even though the method is ExportFunctionDefinitionToInterpreter, a class will actually be exported)
// (TODO: rename that method to ExportDefinitionToInterpreter)
- if (!ExportFunctionDefinitionToInterpreter (auto_generated_class))
+ if (!ExportFunctionDefinitionToInterpreter (auto_generated_class).Success())
return false;
// Store the name of the auto-generated class
@@ -1285,7 +1319,7 @@ ScriptInterpreterPython::GenerateTypeSynthClass (StringList &user_input, std::st
lldb::ScriptInterpreterObjectSP
ScriptInterpreterPython::OSPlugin_CreatePluginObject (const char *class_name, lldb::ProcessSP process_sp)
{
- if (class_name == NULL || class_name[0] == '\0')
+ if (class_name == nullptr || class_name[0] == '\0')
return lldb::ScriptInterpreterObjectSP();
if (!process_sp)
@@ -1319,7 +1353,7 @@ ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP
PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
- if (implementor == NULL || implementor == Py_None)
+ if (implementor == nullptr || implementor == Py_None)
return lldb::ScriptInterpreterObjectSP();
PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
@@ -1329,7 +1363,7 @@ ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP
PyErr_Clear();
}
- if (pmeth == NULL || pmeth == Py_None)
+ if (pmeth == nullptr || pmeth == Py_None)
{
Py_XDECREF(pmeth);
return lldb::ScriptInterpreterObjectSP();
@@ -1354,7 +1388,7 @@ ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP
Py_XDECREF(pmeth);
// right now we know this function exists and is callable..
- PyObject* py_return = PyObject_CallMethod(implementor, callee_name, NULL);
+ PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr);
// if it fails, print the error but otherwise go on
if (PyErr_Occurred())
@@ -1380,7 +1414,7 @@ ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP o
PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
- if (implementor == NULL || implementor == Py_None)
+ if (implementor == nullptr || implementor == Py_None)
return lldb::ScriptInterpreterObjectSP();
PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
@@ -1390,7 +1424,7 @@ ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP o
PyErr_Clear();
}
- if (pmeth == NULL || pmeth == Py_None)
+ if (pmeth == nullptr || pmeth == Py_None)
{
Py_XDECREF(pmeth);
return lldb::ScriptInterpreterObjectSP();
@@ -1415,7 +1449,7 @@ ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP o
Py_XDECREF(pmeth);
// right now we know this function exists and is callable..
- PyObject* py_return = PyObject_CallMethod(implementor, callee_name, NULL);
+ PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr);
// if it fails, print the error but otherwise go on
if (PyErr_Occurred())
@@ -1437,7 +1471,7 @@ template <typename T>
const char *GetPythonValueFormatString(T t)
{
assert(!"Unhandled type passed to GetPythonValueFormatString(T), make a specialization of GetPythonValueFormatString() to support this type.");
- return NULL;
+ return nullptr;
}
template <> const char *GetPythonValueFormatString (char *) { return "s"; }
template <> const char *GetPythonValueFormatString (char) { return "b"; }
@@ -1469,7 +1503,7 @@ ScriptInterpreterPython::OSPlugin_RegisterContextData (lldb::ScriptInterpreterOb
PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
- if (implementor == NULL || implementor == Py_None)
+ if (implementor == nullptr || implementor == Py_None)
return lldb::ScriptInterpreterObjectSP();
PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
@@ -1479,7 +1513,7 @@ ScriptInterpreterPython::OSPlugin_RegisterContextData (lldb::ScriptInterpreterOb
PyErr_Clear();
}
- if (pmeth == NULL || pmeth == Py_None)
+ if (pmeth == nullptr || pmeth == Py_None)
{
Py_XDECREF(pmeth);
return lldb::ScriptInterpreterObjectSP();
@@ -1535,7 +1569,7 @@ ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP
PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
- if (implementor == NULL || implementor == Py_None)
+ if (implementor == nullptr || implementor == Py_None)
return lldb::ScriptInterpreterObjectSP();
PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
@@ -1545,7 +1579,7 @@ ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP
PyErr_Clear();
}
- if (pmeth == NULL || pmeth == Py_None)
+ if (pmeth == nullptr || pmeth == Py_None)
{
Py_XDECREF(pmeth);
return lldb::ScriptInterpreterObjectSP();
@@ -1627,7 +1661,7 @@ lldb::ScriptInterpreterObjectSP
ScriptInterpreterPython::CreateSyntheticScriptedProvider (const char *class_name,
lldb::ValueObjectSP valobj)
{
- if (class_name == NULL || class_name[0] == '\0')
+ if (class_name == nullptr || class_name[0] == '\0')
return lldb::ScriptInterpreterObjectSP();
if (!valobj.get())
@@ -1675,25 +1709,29 @@ ScriptInterpreterPython::GenerateTypeSynthClass (const char* oneliner, std::stri
}
-bool
+Error
ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user_input, std::string& output)
{
static uint32_t num_created_functions = 0;
user_input.RemoveBlankLines ();
StreamString sstr;
-
+ Error error;
if (user_input.GetSize() == 0)
- return false;
+ {
+ error.SetErrorString("No input data.");
+ return error;
+ }
std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_bp_callback_func_",num_created_functions));
sstr.Printf ("def %s (frame, bp_loc, internal_dict):", auto_generated_function_name.c_str());
- if (!GenerateFunction(sstr.GetData(), user_input))
- return false;
+ error = GenerateFunction(sstr.GetData(), user_input);
+ if (!error.Success())
+ return error;
// Store the name of the auto-generated function to be called.
output.assign(auto_generated_function_name);
- return true;
+ return error;
}
bool
@@ -1709,7 +1747,7 @@ ScriptInterpreterPython::GenerateWatchpointCommandCallbackData (StringList &user
std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_wp_callback_func_",num_created_functions));
sstr.Printf ("def %s (frame, wp, internal_dict):", auto_generated_function_name.c_str());
- if (!GenerateFunction(sstr.GetData(), user_input))
+ if (!GenerateFunction(sstr.GetData(), user_input).Success())
return false;
// Store the name of the auto-generated function to be called.
@@ -1732,7 +1770,7 @@ ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name,
return false;
}
- void* old_callee = (callee_wrapper_sp ? callee_wrapper_sp->GetObject() : NULL);
+ void* old_callee = (callee_wrapper_sp ? callee_wrapper_sp->GetObject() : nullptr);
void* new_callee = old_callee;
bool ret_val;
@@ -1764,6 +1802,21 @@ ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name,
}
+void
+ScriptInterpreterPython::Clear ()
+{
+ // Release any global variables that might have strong references to
+ // LLDB objects when clearing the python script interpreter.
+ Locker locker(this,
+ ScriptInterpreterPython::Locker::AcquireLock,
+ ScriptInterpreterPython::Locker::FreeAcquiredLock);
+
+ // This may be called as part of Py_Finalize. In that case the modules are destroyed in random
+ // order and we can't guarantee that we can access these.
+ if (Py_IsInitialized())
+ PyRun_SimpleString("lldb.debugger = None; lldb.target = None; lldb.process = None; lldb.thread = None; lldb.frame = None");
+}
+
bool
ScriptInterpreterPython::BreakpointCallbackFunction
(
@@ -1914,10 +1967,10 @@ ScriptInterpreterPython::GetChildAtIndex (const lldb::ScriptInterpreterObjectSP&
{
Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
void* child_ptr = g_swig_get_child_index (implementor,idx);
- if (child_ptr != NULL && child_ptr != Py_None)
+ if (child_ptr != nullptr && child_ptr != Py_None)
{
lldb::SBValue* sb_value_ptr = (lldb::SBValue*)g_swig_cast_to_sbvalue(child_ptr);
- if (sb_value_ptr == NULL)
+ if (sb_value_ptr == nullptr)
Py_XDECREF(child_ptr);
else
ret_val = g_swig_get_valobj_sp_from_sbvalue (sb_value_ptr);
@@ -2006,15 +2059,15 @@ ScriptInterpreterPython::MightHaveChildrenSynthProviderInstance (const lldb::Scr
static std::string
ReadPythonBacktrace (PyObject* py_backtrace)
{
- PyObject* traceback_module = NULL,
- *stringIO_module = NULL,
- *stringIO_builder = NULL,
- *stringIO_buffer = NULL,
- *printTB = NULL,
- *printTB_args = NULL,
- *printTB_result = NULL,
- *stringIO_getvalue = NULL,
- *printTB_string = NULL;
+ PyObject* traceback_module = nullptr,
+ *stringIO_module = nullptr,
+ *stringIO_builder = nullptr,
+ *stringIO_buffer = nullptr,
+ *printTB = nullptr,
+ *printTB_args = nullptr,
+ *printTB_result = nullptr,
+ *stringIO_getvalue = nullptr,
+ *printTB_string = nullptr;
std::string retval("backtrace unavailable");
@@ -2028,7 +2081,7 @@ ReadPythonBacktrace (PyObject* py_backtrace)
stringIO_builder = PyObject_GetAttrString(stringIO_module, "StringIO");
if (stringIO_builder && stringIO_builder != Py_None)
{
- stringIO_buffer = PyObject_CallObject(stringIO_builder, NULL);
+ stringIO_buffer = PyObject_CallObject(stringIO_builder, nullptr);
if (stringIO_buffer && stringIO_buffer != Py_None)
{
printTB = PyObject_GetAttrString(traceback_module, "print_tb");
@@ -2039,7 +2092,7 @@ ReadPythonBacktrace (PyObject* py_backtrace)
stringIO_getvalue = PyObject_GetAttrString(stringIO_buffer, "getvalue");
if (stringIO_getvalue && stringIO_getvalue != Py_None)
{
- printTB_string = PyObject_CallObject (stringIO_getvalue,NULL);
+ printTB_string = PyObject_CallObject (stringIO_getvalue,nullptr);
if (printTB_string && printTB_string != Py_None && PyString_Check(printTB_string))
retval.assign(PyString_AsString(printTB_string));
}
@@ -2393,29 +2446,20 @@ ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function,
{
error.SetErrorString("invalid Debugger pointer");
return false;
- }
+ }
bool ret_val = false;
std::string err_msg;
-
+
{
Locker py_lock(this,
- Locker::AcquireLock | Locker::InitSession,
+ Locker::AcquireLock | Locker::InitSession | (cmd_retobj.GetInteractive() ? 0 : Locker::NoSTDIN),
Locker::FreeLock | Locker::TearDownSession);
SynchronicityHandler synch_handler(debugger_sp,
synchronicity);
- // we need to save the thread state when we first start the command
- // because we might decide to interrupt it while some action is taking
- // place outside of Python (e.g. printing to screen, waiting for the network, ...)
- // in that case, _PyThreadState_Current will be NULL - and we would be unable
- // to set the asynchronous exception - not a desirable situation
- m_command_thread_state = _PyThreadState_Current;
-
- //PythonInputReaderManager py_input(this);
-
ret_val = g_swig_call_command (impl_function,
m_dictionary_name.c_str(),
debugger_sp,
@@ -2443,7 +2487,7 @@ ScriptInterpreterPython::GetDocumentationForItem(const char* item, std::string&
std::string command(item);
command += ".__doc__";
- char* result_ptr = NULL; // Python is going to point this to valid data if ExecuteOneLineWithReturn returns successfully
+ char* result_ptr = nullptr; // Python is going to point this to valid data if ExecuteOneLineWithReturn returns successfully
if (ExecuteOneLineWithReturn (command.c_str(),
ScriptInterpreter::eScriptReturnTypeCharStrOrNone,
@@ -2561,7 +2605,7 @@ ScriptInterpreterPython::InitializePrivate ()
FileSpec file_spec;
char python_dir_path[PATH_MAX];
- if (Host::GetLLDBPath (ePathTypePythonDir, file_spec))
+ if (HostInfo::GetLLDBPath(ePathTypePythonDir, file_spec))
{
std::string python_path("sys.path.insert(0,\"");
size_t orig_len = python_path.length();
@@ -2572,8 +2616,8 @@ ScriptInterpreterPython::InitializePrivate ()
PyRun_SimpleString (python_path.c_str());
python_path.resize (orig_len);
}
-
- if (Host::GetLLDBPath (ePathTypeLLDBShlibDir, file_spec))
+
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, file_spec))
{
if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path)))
{
@@ -2585,7 +2629,7 @@ ScriptInterpreterPython::InitializePrivate ()
}
}
- PyRun_SimpleString ("sys.dont_write_bytecode = 1; import lldb.embedded_interpreter; from lldb.embedded_interpreter import run_python_interpreter; from lldb.embedded_interpreter import run_one_line; from termios import *");
+ PyRun_SimpleString ("sys.dont_write_bytecode = 1; import lldb.embedded_interpreter; from lldb.embedded_interpreter import run_python_interpreter; from lldb.embedded_interpreter import run_one_line");
if (threads_already_initialized) {
if (log)
diff --git a/source/Interpreter/embedded_interpreter.py b/source/Interpreter/embedded_interpreter.py
index bc0dd6d5ae4f..51a971690d67 100644
--- a/source/Interpreter/embedded_interpreter.py
+++ b/source/Interpreter/embedded_interpreter.py
@@ -9,6 +9,10 @@ try:
import rlcompleter
except ImportError:
have_readline = False
+except AttributeError:
+ # This exception gets hit by the rlcompleter when Linux is using
+ # the readline suppression import.
+ have_readline = False
else:
have_readline = True
if 'libedit' in readline.__doc__:
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
index abf873ff3dd1..a9f8f3b668dc 100644
--- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
+++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
@@ -24,6 +24,7 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "Utility/ARM_DWARF_Registers.h"
@@ -144,7 +145,7 @@ static RegisterInfo g_register_infos[] =
{ "r13_svc", "sp_svc", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_svc, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
{ "r14_svc", "lr_svc", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_svc, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL}
};
-static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo);
+static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
static bool g_register_info_names_constified = false;
const lldb_private::RegisterInfo *
@@ -214,7 +215,7 @@ ABIMacOSX_arm::PrepareTrivialCall (Thread &thread,
llvm::ArrayRef<addr_t>::iterator ai = args.begin(), ae = args.end();
- for (size_t i = 0; i < (sizeof(reg_names) / sizeof(reg_names[0])); ++i)
+ for (size_t i = 0; i < llvm::array_lengthof(reg_names); ++i)
{
if (ai == ae)
break;
@@ -522,7 +523,13 @@ ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObj
if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType())
{
DataExtractor data;
- size_t num_bytes = new_value_sp->GetData(data);
+ Error data_error;
+ size_t num_bytes = new_value_sp->GetData(data, data_error);
+ if (data_error.Fail())
+ {
+ error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString());
+ return error;
+ }
lldb::offset_t offset = 0;
if (num_bytes <= 8)
{
diff --git a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp
new file mode 100644
index 000000000000..8f7962d095fc
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp
@@ -0,0 +1,1103 @@
+//===-- ABIMacOSX_arm64.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ABIMacOSX_arm64.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+
+#include "Utility/ARM64_DWARF_Registers.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const char *pluginDesc = "Mac OS X ABI for arm64 targets";
+static const char *pluginShort = "abi.macosx-arm64";
+
+
+static RegisterInfo g_register_infos[] =
+{
+ // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE
+ // ========== ======= == === ============= =================== =================== ====================== =========================== ======================= ======================
+ { "x0", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x0, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x1", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x1, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x2", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x2, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x3", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x3, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x4", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x4, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x5", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x5, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x6", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x6, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x7", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x7, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x8", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x9", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x10", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x11", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x12", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x13", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x14", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x15", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x16", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x17", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x18", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x19", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x20", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x21", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x22", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x23", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x24", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x25", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x26", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x27", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "x28", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "fp", "x29", 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x29, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "lr", "x30", 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x30, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "sp", "x31", 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x31, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "pc", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "cpsr", "psr", 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+
+ { "v0", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v1", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v2", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v3", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v4", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v5", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v6", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v7", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v8", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v9", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v10", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v11", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v12", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v13", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v14", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v15", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v16", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v17", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v18", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v19", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v20", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v21", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v22", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v23", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v24", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v25", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v26", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v27", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v28", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v29", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v29, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v30", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v30, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "v31", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v31, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+
+ { "fpsr", NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "fpcr", NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+
+ { "s0", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s1", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s2", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s3", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s4", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s5", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s6", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s7", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s8", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s9", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s10", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s11", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s12", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s13", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s14", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s15", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s16", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s17", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s18", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s19", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s20", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s21", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s22", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s23", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s24", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s25", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s26", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s27", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s28", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s29", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s30", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "s31", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+
+ { "d0", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d1", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d2", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d3", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d4", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d5", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d6", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d7", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d8", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d9", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d10", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d11", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d12", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d13", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d14", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d15", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d16", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d17", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d18", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d19", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d20", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d21", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d22", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d23", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d24", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d25", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d26", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d27", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d28", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d29", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d30", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL },
+ { "d31", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }
+};
+
+static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
+static bool g_register_info_names_constified = false;
+
+const lldb_private::RegisterInfo *
+ABIMacOSX_arm64::GetRegisterInfoArray (uint32_t &count)
+{
+ // Make the C-string names and alt_names for the register infos into const
+ // C-string values by having the ConstString unique the names in the global
+ // constant C-string pool.
+ if (!g_register_info_names_constified)
+ {
+ g_register_info_names_constified = true;
+ for (uint32_t i=0; i<k_num_register_infos; ++i)
+ {
+ if (g_register_infos[i].name)
+ g_register_infos[i].name = ConstString(g_register_infos[i].name).GetCString();
+ if (g_register_infos[i].alt_name)
+ g_register_infos[i].alt_name = ConstString(g_register_infos[i].alt_name).GetCString();
+ }
+ }
+ count = k_num_register_infos;
+ return g_register_infos;
+}
+
+size_t
+ABIMacOSX_arm64::GetRedZoneSize () const
+{
+ return 128;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABIMacOSX_arm64::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ if (arch.GetTriple().getArch() == llvm::Triple::aarch64)
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABIMacOSX_arm64);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABIMacOSX_arm64::PrepareTrivialCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t func_addr,
+ lldb::addr_t return_addr,
+ llvm::ArrayRef<lldb::addr_t> args) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return false;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ StreamString s;
+ s.Printf("ABISysV_x86_64::PrepareTrivialCall (tid = 0x%" PRIx64 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 ", return_addr = 0x%" PRIx64,
+ thread.GetID(),
+ (uint64_t)sp,
+ (uint64_t)func_addr,
+ (uint64_t)return_addr);
+
+ for (size_t i = 0; i < args.size(); ++i)
+ s.Printf (", arg%d = 0x%" PRIx64, static_cast<int>(i + 1), args[i]);
+ s.PutCString (")");
+ log->PutCString(s.GetString().c_str());
+ }
+
+ const uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ const uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ const uint32_t ra_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+
+ // x0 - x7 contain first 8 simple args
+ if (args.size() > 8) // TODO handle more than 6 arguments
+ return false;
+
+ for (size_t i = 0; i < args.size(); ++i)
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i);
+ if (log)
+ log->Printf("About to write arg%d (0x%" PRIx64 ") into %s",
+ static_cast<int>(i + 1), args[i], reg_info->name);
+ if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
+ return false;
+ }
+
+ // Set "lr" to the return address
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_ctx->GetRegisterInfoAtIndex (ra_reg_num), return_addr))
+ return false;
+
+ // Set "sp" to the requested value
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_ctx->GetRegisterInfoAtIndex (sp_reg_num), sp))
+ return false;
+
+ // Set "pc" to the address requested
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_ctx->GetRegisterInfoAtIndex (pc_reg_num), func_addr))
+ return false;
+
+ return true;
+}
+
+
+bool
+ABIMacOSX_arm64::GetArgumentValues (Thread &thread, ValueList &values) const
+{
+ uint32_t num_values = values.GetSize();
+
+ ExecutionContext exe_ctx (thread.shared_from_this());
+
+ // Extract the register context so we can read arguments from registers
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+
+ if (!reg_ctx)
+ return false;
+
+ addr_t sp = 0;
+
+ for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx)
+ {
+ // We currently only support extracting values with Clang QualTypes.
+ // Do we care about others?
+ Value *value = values.GetValueAtIndex(value_idx);
+
+ if (!value)
+ return false;
+
+ ClangASTType value_type = value->GetClangType();
+ if (value_type)
+ {
+ bool is_signed = false;
+ size_t bit_width = 0;
+ if (value_type.IsIntegerType (is_signed))
+ {
+ bit_width = value_type.GetBitSize();
+ }
+ else if (value_type.IsPointerOrReferenceType ())
+ {
+ bit_width = value_type.GetBitSize();
+ }
+ else
+ {
+ // We only handle integer, pointer and reference types currently...
+ return false;
+ }
+
+ if (bit_width <= (exe_ctx.GetProcessRef().GetAddressByteSize() * 8))
+ {
+ if (value_idx < 8)
+ {
+ // Arguments 1-6 are in x0-x5...
+ const RegisterInfo *reg_info = NULL;
+ // Search by generic ID first, then fall back to by name
+ uint32_t arg_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx);
+ if (arg_reg_num != LLDB_INVALID_REGNUM)
+ {
+ reg_info = reg_ctx->GetRegisterInfoAtIndex(arg_reg_num);
+ }
+ else
+ {
+ switch (value_idx)
+ {
+ case 0: reg_info = reg_ctx->GetRegisterInfoByName("x0"); break;
+ case 1: reg_info = reg_ctx->GetRegisterInfoByName("x1"); break;
+ case 2: reg_info = reg_ctx->GetRegisterInfoByName("x2"); break;
+ case 3: reg_info = reg_ctx->GetRegisterInfoByName("x3"); break;
+ case 4: reg_info = reg_ctx->GetRegisterInfoByName("x4"); break;
+ case 5: reg_info = reg_ctx->GetRegisterInfoByName("x5"); break;
+ case 6: reg_info = reg_ctx->GetRegisterInfoByName("x6"); break;
+ case 7: reg_info = reg_ctx->GetRegisterInfoByName("x7"); break;
+ }
+ }
+
+ if (reg_info)
+ {
+ RegisterValue reg_value;
+
+ if (reg_ctx->ReadRegister(reg_info, reg_value))
+ {
+ if (is_signed)
+ reg_value.SignExtend(bit_width);
+ if (!reg_value.GetScalarValue(value->GetScalar()))
+ return false;
+ continue;
+ }
+ }
+ return false;
+ }
+ else
+ {
+ if (sp == 0)
+ {
+ // Read the stack pointer if we already haven't read it
+ sp = reg_ctx->GetSP(0);
+ if (sp == 0)
+ return false;
+ }
+
+ // Arguments 5 on up are on the stack
+ const uint32_t arg_byte_size = (bit_width + (8-1)) / 8;
+ Error error;
+ if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory(sp, arg_byte_size, is_signed, value->GetScalar(), error))
+ return false;
+
+ sp += arg_byte_size;
+ // Align up to the next 8 byte boundary if needed
+ if (sp % 8)
+ {
+ sp >>= 3;
+ sp += 1;
+ sp <<= 3;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+Error
+ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp)
+{
+ Error error;
+ if (!new_value_sp)
+ {
+ error.SetErrorString("Empty value object for return value.");
+ return error;
+ }
+
+ ClangASTType return_value_type = new_value_sp->GetClangType();
+ if (!return_value_type)
+ {
+ error.SetErrorString ("Null clang type for return value.");
+ return error;
+ }
+
+ Thread *thread = frame_sp->GetThread().get();
+
+ RegisterContext *reg_ctx = thread->GetRegisterContext().get();
+
+ if (reg_ctx)
+ {
+ DataExtractor data;
+ Error data_error;
+ const uint64_t byte_size = new_value_sp->GetData(data, data_error);
+ if (data_error.Fail())
+ {
+ error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString());
+ return error;
+ }
+
+ const uint32_t type_flags = return_value_type.GetTypeInfo (NULL);
+ if (type_flags & ClangASTType::eTypeIsScalar ||
+ type_flags & ClangASTType::eTypeIsPointer)
+ {
+ if (type_flags & ClangASTType::eTypeIsInteger ||
+ type_flags & ClangASTType::eTypeIsPointer )
+ {
+ // Extract the register context so we can read arguments from registers
+ lldb::offset_t offset = 0;
+ if (byte_size <= 16)
+ {
+ const RegisterInfo *x0_info = reg_ctx->GetRegisterInfoByName("x0", 0);
+ if (byte_size <= 8)
+ {
+ uint64_t raw_value = data.GetMaxU64(&offset, byte_size);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (x0_info, raw_value))
+ error.SetErrorString ("failed to write register x0");
+ }
+ else
+ {
+ uint64_t raw_value = data.GetMaxU64(&offset, 8);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (x0_info, raw_value))
+ {
+ const RegisterInfo *x1_info = reg_ctx->GetRegisterInfoByName("x1", 0);
+ raw_value = data.GetMaxU64(&offset, byte_size - offset);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (x1_info, raw_value))
+ error.SetErrorString ("failed to write register x1");
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("We don't support returning longer than 128 bit integer values at present.");
+ }
+ }
+ else if (type_flags & ClangASTType::eTypeIsFloat)
+ {
+ if (type_flags & ClangASTType::eTypeIsComplex)
+ {
+ // Don't handle complex yet.
+ error.SetErrorString ("returning complex float values are not supported");
+ }
+ else
+ {
+ const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0);
+
+ if (v0_info)
+ {
+ if (byte_size <= 16)
+ {
+ if (byte_size <= RegisterValue::GetMaxByteSize())
+ {
+ RegisterValue reg_value;
+ error = reg_value.SetValueFromData (v0_info, data, 0, true);
+ if (error.Success())
+ {
+ if (!reg_ctx->WriteRegister (v0_info, reg_value))
+ error.SetErrorString ("failed to write register v0");
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("returning float values with a byte size of %" PRIu64 " are not supported", byte_size);
+ }
+ }
+ else
+ {
+ error.SetErrorString("returning float values longer than 128 bits are not supported");
+ }
+ }
+ else
+ {
+ error.SetErrorString("v0 register is not available on this target");
+ }
+ }
+ }
+ }
+ else if (type_flags & ClangASTType::eTypeIsVector)
+ {
+ if (byte_size > 0)
+ {
+ const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0);
+
+ if (v0_info)
+ {
+ if (byte_size <= v0_info->byte_size)
+ {
+ RegisterValue reg_value;
+ error = reg_value.SetValueFromData (v0_info, data, 0, true);
+ if (error.Success())
+ {
+ if (!reg_ctx->WriteRegister (v0_info, reg_value))
+ error.SetErrorString ("failed to write register v0");
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("no registers are available");
+ }
+
+ return error;
+}
+
+bool
+ABIMacOSX_arm64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ uint32_t lr_reg_num = arm64_dwarf::lr;
+ uint32_t sp_reg_num = arm64_dwarf::sp;
+ uint32_t pc_reg_num = arm64_dwarf::pc;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ // Our previous Call Frame Address is the stack pointer
+ row->SetCFARegister (sp_reg_num);
+
+ // Our previous PC is in the LR
+ row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true);
+
+ unwind_plan.AppendRow (row);
+
+ // All other registers are the same.
+
+ unwind_plan.SetSourceName ("arm64 at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+
+ return true;
+}
+
+bool
+ABIMacOSX_arm64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ uint32_t fp_reg_num = arm64_dwarf::fp;
+ uint32_t pc_reg_num = arm64_dwarf::pc;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ const int32_t ptr_size = 8;
+
+ row->SetCFARegister (fp_reg_num);
+ row->SetCFAOffset (2 * ptr_size);
+ row->SetOffset (0);
+
+ row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
+
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("arm64-apple-darwin default unwind plan");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ return true;
+}
+
+// AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says
+// registers x19 through x28 and sp are callee preserved.
+// v8-v15 are non-volatile (and specifically only the lower 8 bytes of these regs),
+// the rest of the fp/SIMD registers are volatile.
+
+// We treat x29 as callee preserved also, else the unwinder won't try to
+// retrieve fp saves.
+
+bool
+ABIMacOSX_arm64::RegisterIsVolatile (const RegisterInfo *reg_info)
+{
+ if (reg_info)
+ {
+ const char *name = reg_info->name;
+
+ // Sometimes we'll be called with the "alternate" name for these registers;
+ // recognize them as non-volatile.
+
+ if (name[0] == 'p' && name[1] == 'c') // pc
+ return false;
+ if (name[0] == 'f' && name[1] == 'p') // fp
+ return false;
+ if (name[0] == 's' && name[1] == 'p') // sp
+ return false;
+ if (name[0] == 'l' && name[1] == 'r') // lr
+ return false;
+
+ if (name[0] == 'x')
+ {
+ // Volatile registers: x0-x18, x30 (lr)
+ // Return false for the non-volatile gpr regs, true for everything else
+ switch (name[1])
+ {
+ case '1':
+ switch (name[2])
+ {
+ case '9':
+ return false; // x19 is non-volatile
+ default:
+ return true;
+ }
+ break;
+ case '2':
+ switch (name[2])
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ return false; // x20 - 28 are non-volatile
+ case '9':
+ return false; // x29 aka fp treat as non-volatile on Darwin
+ default:
+ return true;
+ }
+ case '3': // x30 aka lr treat as non-volatile
+ if (name[2] == '0')
+ return false;
+ default:
+ return true;
+ }
+ }
+ else if (name[0] == 'v' || name[0] == 's' || name[0] == 'd')
+ {
+ // Volatile registers: v0-7, v16-v31
+ // Return false for non-volatile fp/SIMD regs, true for everything else
+ switch (name[1])
+ {
+ case '8':
+ case '9':
+ return false; // v8-v9 are non-volatile
+ case '1':
+ switch (name[2])
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ return false; // v10-v15 are non-volatile
+ default:
+ return true;
+ }
+ default:
+ return true;
+ }
+ }
+ }
+ return true;
+}
+
+static bool
+LoadValueFromConsecutiveGPRRegisters (ExecutionContext &exe_ctx,
+ RegisterContext *reg_ctx,
+ const ClangASTType &value_type,
+ bool is_return_value, // false => parameter, true => return value
+ uint32_t &NGRN, // NGRN (see ABI documentation)
+ uint32_t &NSRN, // NSRN (see ABI documentation)
+ DataExtractor &data)
+{
+ const size_t byte_size = value_type.GetByteSize();
+
+ if (byte_size == 0)
+ return false;
+
+ std::unique_ptr<DataBufferHeap> heap_data_ap (new DataBufferHeap(byte_size, 0));
+ const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder();
+ Error error;
+
+ ClangASTType base_type;
+ const uint32_t homogeneous_count = value_type.IsHomogeneousAggregate (&base_type);
+ if (homogeneous_count > 0 && homogeneous_count <= 8)
+ {
+ printf ("ClangASTContext::IsHomogeneousAggregate() => %u\n", homogeneous_count);
+ // Make sure we have enough registers
+ if (NSRN < 8 && (8-NSRN) >= homogeneous_count)
+ {
+ if (!base_type)
+ return false;
+ const size_t base_byte_size = base_type.GetByteSize();
+ printf ("ClangASTContext::IsHomogeneousAggregate() => base_byte_size = %" PRIu64 "\n", (uint64_t) base_byte_size);
+ uint32_t data_offset = 0;
+
+ for (uint32_t i=0; i<homogeneous_count; ++i)
+ {
+ char v_name[8];
+ ::snprintf (v_name, sizeof(v_name), "v%u", NSRN);
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(v_name, 0);
+ if (reg_info == NULL)
+ return false;
+
+ if (base_byte_size > reg_info->byte_size)
+ return false;
+
+ RegisterValue reg_value;
+
+ if (!reg_ctx->ReadRegister(reg_info, reg_value))
+ return false;
+
+ // Make sure we have enough room in "heap_data_ap"
+ if ((data_offset + base_byte_size) <= heap_data_ap->GetByteSize())
+ {
+ const size_t bytes_copied = reg_value.GetAsMemoryData (reg_info,
+ heap_data_ap->GetBytes()+data_offset,
+ base_byte_size,
+ byte_order,
+ error);
+ if (bytes_copied != base_byte_size)
+ return false;
+ data_offset += bytes_copied;
+ ++NSRN;
+ }
+ else
+ return false;
+ }
+ data.SetByteOrder(byte_order);
+ data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize());
+ data.SetData(DataBufferSP (heap_data_ap.release()));
+ return true;
+ }
+ }
+
+ const size_t max_reg_byte_size = 16;
+ if (byte_size <= max_reg_byte_size)
+ {
+ size_t bytes_left = byte_size;
+ uint32_t data_offset = 0;
+ while (data_offset < byte_size)
+ {
+ if (NGRN >= 8)
+ return false;
+
+ uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN);
+ if (reg_num == LLDB_INVALID_REGNUM)
+ return false;
+
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
+ if (reg_info == NULL)
+ return false;
+
+ RegisterValue reg_value;
+
+ if (!reg_ctx->ReadRegister(reg_info, reg_value))
+ return false;
+
+ const size_t curr_byte_size = std::min<size_t>(8,bytes_left);
+ const size_t bytes_copied = reg_value.GetAsMemoryData (reg_info, heap_data_ap->GetBytes()+data_offset, curr_byte_size, byte_order, error);
+ if (bytes_copied == 0)
+ return false;
+ if (bytes_copied >= bytes_left)
+ break;
+ data_offset += bytes_copied;
+ bytes_left -= bytes_copied;
+ ++NGRN;
+ }
+ }
+ else
+ {
+ const RegisterInfo *reg_info = NULL;
+ if (is_return_value)
+ {
+ // We are assuming we are decoding this immediately after returning
+ // from a function call and that the address of the structure is in x8
+ reg_info = reg_ctx->GetRegisterInfoByName("x8", 0);
+ }
+ else
+ {
+ // We are assuming we are stopped at the first instruction in a function
+ // and that the ABI is being respected so all parameters appear where they
+ // should be (functions with no external linkage can legally violate the ABI).
+ if (NGRN >= 8)
+ return false;
+
+ uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN);
+ if (reg_num == LLDB_INVALID_REGNUM)
+ return false;
+ reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
+ if (reg_info == NULL)
+ return false;
+ ++NGRN;
+ }
+
+ if (reg_info == NULL)
+ return false;
+
+ const lldb::addr_t value_addr = reg_ctx->ReadRegisterAsUnsigned(reg_info, LLDB_INVALID_ADDRESS);
+
+ if (value_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (exe_ctx.GetProcessRef().ReadMemory (value_addr,
+ heap_data_ap->GetBytes(),
+ heap_data_ap->GetByteSize(),
+ error) != heap_data_ap->GetByteSize())
+ {
+ return false;
+ }
+ }
+
+ data.SetByteOrder(byte_order);
+ data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize());
+ data.SetData(DataBufferSP (heap_data_ap.release()));
+ return true;
+}
+
+ValueObjectSP
+ABIMacOSX_arm64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_clang_type) const
+{
+ ValueObjectSP return_valobj_sp;
+ Value value;
+
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ if (exe_ctx.GetTargetPtr() == NULL || exe_ctx.GetProcessPtr() == NULL)
+ return return_valobj_sp;
+
+ //value.SetContext (Value::eContextTypeClangType, return_clang_type);
+ value.SetClangType(return_clang_type);
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return return_valobj_sp;
+
+ const size_t byte_size = return_clang_type.GetByteSize();
+
+ const uint32_t type_flags = return_clang_type.GetTypeInfo (NULL);
+ if (type_flags & ClangASTType::eTypeIsScalar ||
+ type_flags & ClangASTType::eTypeIsPointer)
+ {
+ value.SetValueType(Value::eValueTypeScalar);
+
+ bool success = false;
+ if (type_flags & ClangASTType::eTypeIsInteger ||
+ type_flags & ClangASTType::eTypeIsPointer )
+ {
+ // Extract the register context so we can read arguments from registers
+ if (byte_size <= 8)
+ {
+ const RegisterInfo *x0_reg_info = reg_ctx->GetRegisterInfoByName("x0", 0);
+ if (x0_reg_info)
+ {
+ uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info, 0);
+ const bool is_signed = (type_flags & ClangASTType::eTypeIsSigned) != 0;
+ switch (byte_size)
+ {
+ default:
+ break;
+ case 16: // uint128_t
+ // In register x0 and x1
+ {
+ const RegisterInfo *x1_reg_info = reg_ctx->GetRegisterInfoByName("x1", 0);
+
+ if (x1_reg_info)
+ {
+ if (byte_size <= x0_reg_info->byte_size + x1_reg_info->byte_size)
+ {
+ std::unique_ptr<DataBufferHeap> heap_data_ap (new DataBufferHeap(byte_size, 0));
+ const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder();
+ RegisterValue x0_reg_value;
+ RegisterValue x1_reg_value;
+ if (reg_ctx->ReadRegister(x0_reg_info, x0_reg_value) &&
+ reg_ctx->ReadRegister(x1_reg_info, x1_reg_value))
+ {
+ Error error;
+ if (x0_reg_value.GetAsMemoryData (x0_reg_info, heap_data_ap->GetBytes()+0, 8, byte_order, error) &&
+ x1_reg_value.GetAsMemoryData (x1_reg_info, heap_data_ap->GetBytes()+8, 8, byte_order, error))
+ {
+ DataExtractor data (DataBufferSP (heap_data_ap.release()),
+ byte_order,
+ exe_ctx.GetProcessRef().GetAddressByteSize());
+
+ return_valobj_sp = ValueObjectConstResult::Create (&thread,
+ return_clang_type,
+ ConstString(""),
+ data);
+ return return_valobj_sp;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case sizeof(uint64_t):
+ if (is_signed)
+ value.GetScalar() = (int64_t)(raw_value);
+ else
+ value.GetScalar() = (uint64_t)(raw_value);
+ success = true;
+ break;
+
+ case sizeof(uint32_t):
+ if (is_signed)
+ value.GetScalar() = (int32_t)(raw_value & UINT32_MAX);
+ else
+ value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX);
+ success = true;
+ break;
+
+ case sizeof(uint16_t):
+ if (is_signed)
+ value.GetScalar() = (int16_t)(raw_value & UINT16_MAX);
+ else
+ value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX);
+ success = true;
+ break;
+
+ case sizeof(uint8_t):
+ if (is_signed)
+ value.GetScalar() = (int8_t)(raw_value & UINT8_MAX);
+ else
+ value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX);
+ success = true;
+ break;
+ }
+ }
+ }
+ }
+ else if (type_flags & ClangASTType::eTypeIsFloat)
+ {
+ if (type_flags & ClangASTType::eTypeIsComplex)
+ {
+ // Don't handle complex yet.
+ }
+ else
+ {
+ if (byte_size <= sizeof(long double))
+ {
+ const RegisterInfo *v0_reg_info = reg_ctx->GetRegisterInfoByName("v0", 0);
+ RegisterValue v0_value;
+ if (reg_ctx->ReadRegister (v0_reg_info, v0_value))
+ {
+ DataExtractor data;
+ if (v0_value.GetData(data))
+ {
+ lldb::offset_t offset = 0;
+ if (byte_size == sizeof(float))
+ {
+ value.GetScalar() = data.GetFloat(&offset);
+ success = true;
+ }
+ else if (byte_size == sizeof(double))
+ {
+ value.GetScalar() = data.GetDouble(&offset);
+ success = true;
+ }
+ else if (byte_size == sizeof(long double))
+ {
+ value.GetScalar() = data.GetLongDouble(&offset);
+ success = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (success)
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+
+ }
+ else if (type_flags & ClangASTType::eTypeIsVector)
+ {
+ if (byte_size > 0)
+ {
+
+ const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0);
+
+ if (v0_info)
+ {
+ if (byte_size <= v0_info->byte_size)
+ {
+ std::unique_ptr<DataBufferHeap> heap_data_ap (new DataBufferHeap(byte_size, 0));
+ const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder();
+ RegisterValue reg_value;
+ if (reg_ctx->ReadRegister(v0_info, reg_value))
+ {
+ Error error;
+ if (reg_value.GetAsMemoryData (v0_info,
+ heap_data_ap->GetBytes(),
+ heap_data_ap->GetByteSize(),
+ byte_order,
+ error))
+ {
+ DataExtractor data (DataBufferSP (heap_data_ap.release()),
+ byte_order,
+ exe_ctx.GetProcessRef().GetAddressByteSize());
+ return_valobj_sp = ValueObjectConstResult::Create (&thread,
+ return_clang_type,
+ ConstString(""),
+ data);
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (type_flags & ClangASTType::eTypeIsStructUnion ||
+ type_flags & ClangASTType::eTypeIsClass)
+ {
+ DataExtractor data;
+
+ uint32_t NGRN = 0; // Search ABI docs for NGRN
+ uint32_t NSRN = 0; // Search ABI docs for NSRN
+ const bool is_return_value = true;
+ if (LoadValueFromConsecutiveGPRRegisters (exe_ctx, reg_ctx, return_clang_type, is_return_value, NGRN, NSRN, data))
+ {
+ return_valobj_sp = ValueObjectConstResult::Create (&thread,
+ return_clang_type,
+ ConstString(""),
+ data);
+ }
+ }
+ return return_valobj_sp;
+}
+
+void
+ABIMacOSX_arm64::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ pluginDesc,
+ CreateInstance);
+}
+
+void
+ABIMacOSX_arm64::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+ConstString
+ABIMacOSX_arm64::GetPluginNameStatic()
+{
+ static ConstString g_plugin_name("ABIMacOSX_arm64");
+ return g_plugin_name;
+}
+
+const char *
+ABIMacOSX_arm64::GetShortPluginName()
+{
+ return pluginShort;
+}
+
+uint32_t
+ABIMacOSX_arm64::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h
new file mode 100644
index 000000000000..0753b23ce2a2
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h
@@ -0,0 +1,145 @@
+//===-- ABIMacOSX_arm64.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_ABIMacOSX_arm64_h_
+#define liblldb_ABIMacOSX_arm64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Target/ABI.h"
+
+class ABIMacOSX_arm64 :
+ public lldb_private::ABI
+{
+public:
+ ~ABIMacOSX_arm64() { }
+
+ virtual size_t
+ GetRedZoneSize () const;
+
+ virtual bool
+ PrepareTrivialCall (lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ llvm::ArrayRef<lldb::addr_t> args) const;
+
+ virtual bool
+ GetArgumentValues (lldb_private::Thread &thread,
+ lldb_private::ValueList &values) const;
+
+ virtual bool
+ CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan);
+
+ virtual bool
+ CreateDefaultUnwindPlan (lldb_private::UnwindPlan &unwind_plan);
+
+ virtual bool
+ RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info);
+
+
+ virtual bool
+ StackUsesFrames ()
+ {
+ // MacOSX uses frame pointers.
+ return true;
+ }
+
+ // The arm64 ABI requires that stack frames be 16 byte aligned.
+ // When there is a trap handler on the stack, e.g. _sigtramp in userland
+ // code, we've seen that the stack pointer is often not aligned properly
+ // before the handler is invoked. This means that lldb will stop the unwind
+ // early -- before the function which caused the trap.
+ //
+ // To work around this, we relax that alignment to be just word-size (8-bytes).
+ // Whitelisting the trap handlers for user space would be easy (_sigtramp) but
+ // in other environments there can be a large number of different functions
+ // involved in async traps.
+
+ virtual bool
+ CallFrameAddressIsValid (lldb::addr_t cfa)
+ {
+ // Make sure the stack call frame addresses are are 8 byte aligned
+ if (cfa & (8ull - 1ull))
+ return false; // Not 8 byte aligned
+ if (cfa == 0)
+ return false; // Zero is not a valid stack address
+ return true;
+ }
+
+ virtual bool
+ CodeAddressIsValid (lldb::addr_t pc)
+ {
+ if (pc & (4ull - 1ull))
+ return false; // Not 4 byte aligned
+
+ // Anything else if fair game..
+ return true;
+ }
+
+ virtual bool
+ FunctionCallsChangeCFA ()
+ {
+ return false;
+ }
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoArray (uint32_t &count);
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb::ABISP
+ CreateInstance (const lldb_private::ArchSpec &arch);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ virtual lldb_private::ConstString
+ GetPluginName()
+ {
+ return GetPluginNameStatic();
+ }
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual lldb_private::Error
+ SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value);
+
+protected:
+ virtual lldb::ValueObjectSP
+ GetReturnValueObjectImpl (lldb_private::Thread &thread,
+ lldb_private::ClangASTType &ast_type) const;
+
+private:
+ ABIMacOSX_arm64() :
+ lldb_private::ABI()
+ {
+ // Call CreateInstance instead.
+ }
+};
+
+#endif // liblldb_ABI_h_
diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
index 8596381b3cbc..9a1ea11cbae7 100644
--- a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
+++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
@@ -199,7 +199,7 @@ static RegisterInfo g_register_infos[] =
{ "ymm7" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm7 , LLDB_INVALID_REGNUM , gdb_ymm7 , LLDB_INVALID_REGNUM }, NULL, NULL}
};
-static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo);
+static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
static bool g_register_info_names_constified = false;
const lldb_private::RegisterInfo *
@@ -600,7 +600,13 @@ ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueOb
if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType())
{
DataExtractor data;
- size_t num_bytes = new_value_sp->GetData(data);
+ Error data_error;
+ size_t num_bytes = new_value_sp->GetData(data, data_error);
+ if (data_error.Fail())
+ {
+ error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString());
+ return error;
+ }
lldb::offset_t offset = 0;
if (num_bytes <= 8)
{
diff --git a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
new file mode 100644
index 000000000000..0f01c568ed3e
--- /dev/null
+++ b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
@@ -0,0 +1,554 @@
+//===-- ABISysV_hexagon.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ABISysV_hexagon.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectRegister.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+
+#include "llvm/ADT/Triple.h"
+
+#include "llvm/IR/Type.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static RegisterInfo g_register_infos[] =
+{
+ // hexagon-core.xml
+ { "r00" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 0, 0, LLDB_INVALID_REGNUM, 0, 0 }, NULL, NULL },
+ { "r01" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 1, 1, LLDB_INVALID_REGNUM, 1, 1 }, NULL, NULL },
+ { "r02" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 2, 2, LLDB_INVALID_REGNUM, 2, 2 }, NULL, NULL },
+ { "r03" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 3, 3, LLDB_INVALID_REGNUM, 3, 3 }, NULL, NULL },
+ { "r04" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 4, 4, LLDB_INVALID_REGNUM, 4, 4 }, NULL, NULL },
+ { "r05" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 5, 5, LLDB_INVALID_REGNUM, 5, 5 }, NULL, NULL },
+ { "r06" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 6, 6, LLDB_INVALID_REGNUM, 6, 6 }, NULL, NULL },
+ { "r07" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 7, 7, LLDB_INVALID_REGNUM, 7, 7 }, NULL, NULL },
+ { "r08" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 8, 8, LLDB_INVALID_REGNUM, 8, 8 }, NULL, NULL },
+ { "r09" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 9, 9, LLDB_INVALID_REGNUM, 9, 9 }, NULL, NULL },
+ { "r10" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 10, 10, LLDB_INVALID_REGNUM, 10, 10 }, NULL, NULL },
+ { "r11" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 11, 11, LLDB_INVALID_REGNUM, 11, 11 }, NULL, NULL },
+ { "r12" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 12, 12, LLDB_INVALID_REGNUM, 12, 12 }, NULL, NULL },
+ { "r13" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 13, 13, LLDB_INVALID_REGNUM, 13, 13 }, NULL, NULL },
+ { "r14" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 14, 14, LLDB_INVALID_REGNUM, 14, 14 }, NULL, NULL },
+ { "r15" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 15, 15, LLDB_INVALID_REGNUM, 15, 15 }, NULL, NULL },
+ { "r16" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 16, 16, LLDB_INVALID_REGNUM, 16, 16 }, NULL, NULL },
+ { "r17" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 17, 17, LLDB_INVALID_REGNUM, 17, 17 }, NULL, NULL },
+ { "r18" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 18, 18, LLDB_INVALID_REGNUM, 18, 18 }, NULL, NULL },
+ { "r19" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 19, 19, LLDB_INVALID_REGNUM, 19, 19 }, NULL, NULL },
+ { "r20" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 20, 20, LLDB_INVALID_REGNUM, 20, 20 }, NULL, NULL },
+ { "r21" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 21, 21, LLDB_INVALID_REGNUM, 21, 21 }, NULL, NULL },
+ { "r22" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 22, 22, LLDB_INVALID_REGNUM, 22, 22 }, NULL, NULL },
+ { "r23" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 23, 23, LLDB_INVALID_REGNUM, 23, 23 }, NULL, NULL },
+ { "r24" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 24, 24, LLDB_INVALID_REGNUM, 24, 24 }, NULL, NULL },
+ { "r25" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 25, 25, LLDB_INVALID_REGNUM, 25, 25 }, NULL, NULL },
+ { "r26" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 26, 26, LLDB_INVALID_REGNUM, 26, 26 }, NULL, NULL },
+ { "r27" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 27, 27, LLDB_INVALID_REGNUM, 27, 27 }, NULL, NULL },
+ { "r28" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 28, 28, LLDB_INVALID_REGNUM, 28, 28 }, NULL, NULL },
+ { "sp" ,"r29", 4, 0, eEncodingUint, eFormatAddressInfo, { 29, 29, LLDB_REGNUM_GENERIC_SP, 29, 29 }, NULL, NULL },
+ { "fp" ,"r30", 4, 0, eEncodingUint, eFormatAddressInfo, { 30, 30, LLDB_REGNUM_GENERIC_FP, 30, 30 }, NULL, NULL },
+ { "lr" ,"r31", 4, 0, eEncodingUint, eFormatAddressInfo, { 31, 31, LLDB_REGNUM_GENERIC_RA, 31, 31 }, NULL, NULL },
+ { "sa0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 32, 32, LLDB_INVALID_REGNUM, 32, 32 }, NULL, NULL },
+ { "lc0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 33, 33, LLDB_INVALID_REGNUM, 33, 33 }, NULL, NULL },
+ { "sa1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 34, 34, LLDB_INVALID_REGNUM, 34, 34 }, NULL, NULL },
+ { "lc1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 35, 35, LLDB_INVALID_REGNUM, 35, 35 }, NULL, NULL },
+ // --> hexagon-v4/5/55/56-sim.xml
+ { "p3_0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 36, 36, LLDB_INVALID_REGNUM, 36, 36 }, NULL, NULL },
+// PADDING {
+ { "p00" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 37, 37, LLDB_INVALID_REGNUM, 37, 37 }, NULL, NULL },
+// }
+ { "m0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 38, 38, LLDB_INVALID_REGNUM, 38, 38 }, NULL, NULL },
+ { "m1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 39, 39, LLDB_INVALID_REGNUM, 39, 39 }, NULL, NULL },
+ { "usr" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 40, 40, LLDB_INVALID_REGNUM, 40, 40 }, NULL, NULL },
+ { "pc" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 41, 41, LLDB_REGNUM_GENERIC_PC, 41, 41 }, NULL, NULL },
+ { "ugp" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 42, 42, LLDB_INVALID_REGNUM, 42, 42 }, NULL, NULL },
+ { "gp" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 43, 43, LLDB_INVALID_REGNUM, 43, 43 }, NULL, NULL },
+ { "cs0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 44, 44, LLDB_INVALID_REGNUM, 44, 44 }, NULL, NULL },
+ { "cs1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 45, 45, LLDB_INVALID_REGNUM, 45, 45 }, NULL, NULL },
+// PADDING {
+ { "p01" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 46, 46, LLDB_INVALID_REGNUM, 46, 46 }, NULL, NULL },
+ { "p02" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 47, 47, LLDB_INVALID_REGNUM, 47, 47 }, NULL, NULL },
+ { "p03" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 48, 48, LLDB_INVALID_REGNUM, 48, 48 }, NULL, NULL },
+ { "p04" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 49, 49, LLDB_INVALID_REGNUM, 49, 49 }, NULL, NULL },
+ { "p05" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 50, 50, LLDB_INVALID_REGNUM, 50, 50 }, NULL, NULL },
+ { "p06" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 51, 51, LLDB_INVALID_REGNUM, 51, 51 }, NULL, NULL },
+ { "p07" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 52, 52, LLDB_INVALID_REGNUM, 52, 52 }, NULL, NULL },
+ { "p08" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 53, 53, LLDB_INVALID_REGNUM, 53, 53 }, NULL, NULL },
+ { "p09" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 54, 54, LLDB_INVALID_REGNUM, 54, 54 }, NULL, NULL },
+ { "p10" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 55, 55, LLDB_INVALID_REGNUM, 55, 55 }, NULL, NULL },
+ { "p11" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 56, 56, LLDB_INVALID_REGNUM, 56, 56 }, NULL, NULL },
+ { "p12" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 57, 57, LLDB_INVALID_REGNUM, 57, 57 }, NULL, NULL },
+ { "p13" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 58, 58, LLDB_INVALID_REGNUM, 58, 58 }, NULL, NULL },
+ { "p14" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 59, 59, LLDB_INVALID_REGNUM, 59, 59 }, NULL, NULL },
+ { "p15" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 60, 60, LLDB_INVALID_REGNUM, 60, 60 }, NULL, NULL },
+ { "p16" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 61, 61, LLDB_INVALID_REGNUM, 61, 61 }, NULL, NULL },
+ { "p17" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 62, 62, LLDB_INVALID_REGNUM, 62, 62 }, NULL, NULL },
+ { "p18" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 63, 63, LLDB_INVALID_REGNUM, 63, 63 }, NULL, NULL },
+// }
+ { "sgp0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 64, 64, LLDB_INVALID_REGNUM, 64, 64 }, NULL, NULL },
+// PADDING {
+ { "p19" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 65, 65, LLDB_INVALID_REGNUM, 65, 65 }, NULL, NULL },
+// }
+ { "stid" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 66, 66, LLDB_INVALID_REGNUM, 66, 66 }, NULL, NULL },
+ { "elr" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 67, 67, LLDB_INVALID_REGNUM, 67, 67 }, NULL, NULL },
+ { "badva0", "", 4, 0, eEncodingUint, eFormatAddressInfo, { 68, 68, LLDB_INVALID_REGNUM, 68, 68 }, NULL, NULL },
+ { "badva1", "", 4, 0, eEncodingUint, eFormatAddressInfo, { 69, 69, LLDB_INVALID_REGNUM, 69, 69 }, NULL, NULL },
+ { "ssr" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 70, 70, LLDB_INVALID_REGNUM, 70, 70 }, NULL, NULL },
+ { "ccr" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 71, 71, LLDB_INVALID_REGNUM, 71, 71 }, NULL, NULL },
+ { "htid" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 72, 72, LLDB_INVALID_REGNUM, 72, 72 }, NULL, NULL },
+// PADDING {
+ { "p20" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 73, 73, LLDB_INVALID_REGNUM, 73, 73 }, NULL, NULL },
+// }
+ { "imask" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 74, 74, LLDB_INVALID_REGNUM, 74, 74 }, NULL, NULL },
+// PADDING {
+ { "p21" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 75, 75, LLDB_INVALID_REGNUM, 75, 75 }, NULL, NULL },
+ { "p22" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 76, 76, LLDB_INVALID_REGNUM, 76, 76 }, NULL, NULL },
+ { "p23" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 77, 77, LLDB_INVALID_REGNUM, 77, 77 }, NULL, NULL },
+ { "p24" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 78, 78, LLDB_INVALID_REGNUM, 78, 78 }, NULL, NULL },
+ { "p25" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 79, 79, LLDB_INVALID_REGNUM, 79, 79 }, NULL, NULL },
+ // }
+ { "g0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 80, 80, LLDB_INVALID_REGNUM, 80, 80 }, NULL, NULL },
+ { "g1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 81, 81, LLDB_INVALID_REGNUM, 81, 81 }, NULL, NULL },
+ { "g2" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 82, 82, LLDB_INVALID_REGNUM, 82, 82 }, NULL, NULL },
+ { "g3" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 83, 83, LLDB_INVALID_REGNUM, 83, 83 }, NULL, NULL }
+};
+
+static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo);
+static bool g_register_info_names_constified = false;
+
+const lldb_private::RegisterInfo *
+ABISysV_hexagon::GetRegisterInfoArray ( uint32_t &count )
+{
+ // Make the C-string names and alt_names for the register infos into const
+ // C-string values by having the ConstString unique the names in the global
+ // constant C-string pool.
+ if (!g_register_info_names_constified)
+ {
+ g_register_info_names_constified = true;
+ for (uint32_t i=0; i<k_num_register_infos; ++i)
+ {
+ if (g_register_infos[i].name)
+ g_register_infos[i].name = ConstString(g_register_infos[i].name).GetCString();
+ if (g_register_infos[i].alt_name)
+ g_register_infos[i].alt_name = ConstString(g_register_infos[i].alt_name).GetCString();
+ }
+ }
+ count = k_num_register_infos;
+ return g_register_infos;
+}
+
+/*
+ http://en.wikipedia.org/wiki/Red_zone_%28computing%29
+
+ In computing, a red zone is a fixed size area in memory beyond the stack pointer that has not been
+ "allocated". This region of memory is not to be modified by interrupt/exception/signal handlers.
+ This allows the space to be used for temporary data without the extra overhead of modifying the
+ stack pointer. The x86-64 ABI mandates a 128 byte red zone.[1] The OpenRISC toolchain assumes a
+ 128 byte red zone though it is not documented.
+*/
+size_t
+ABISysV_hexagon::GetRedZoneSize () const
+{
+ return 0;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABISysV_hexagon::CreateInstance ( const ArchSpec &arch )
+{
+ static ABISP g_abi_sp;
+ if (arch.GetTriple().getArch() == llvm::Triple::hexagon)
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABISysV_hexagon);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABISysV_hexagon::PrepareTrivialCall ( Thread &thread,
+ lldb::addr_t sp ,
+ lldb::addr_t pc ,
+ lldb::addr_t ra ,
+ llvm::ArrayRef<addr_t> args ) const
+{
+ // we don't use the traditional trivial call specialized for jit
+ return false;
+}
+
+/*
+
+// AD:
+// . safeguard the current stack
+// . how can we know that the called function will create its own frame properly?
+// . we could manually make a new stack first:
+// 2. push RA
+// 3. push FP
+// 4. FP = SP
+// 5. SP = SP ( since no locals in our temp frame )
+
+// AD 6/05/2014
+// . variable argument list parameters are not passed via registers, they are passed on
+// the stack. This presents us with a problem, since we need to know when the valist
+// starts. Currently I can find out if a function is varg, but not how many
+// real parameters it takes. Thus I don't know when to start spilling the vargs. For
+// the time being, to progress, I will assume that it takes on real parameter before
+// the vargs list starts.
+
+// AD 06/05/2014
+// . how do we adhere to the stack alignment requirements
+
+// AD 06/05/2014
+// . handle 64bit values and their register / stack requirements
+
+*/
+#define HEX_ABI_DEBUG 1
+bool
+ABISysV_hexagon::PrepareTrivialCall ( Thread &thread,
+ lldb::addr_t sp ,
+ lldb::addr_t pc ,
+ lldb::addr_t ra ,
+ llvm::Type &prototype,
+ llvm::ArrayRef<ABI::CallArgument> args) const
+{
+ // default number of register passed arguments for varg functions
+ const int nVArgRegParams = 1;
+ Error error;
+
+ // grab the process so we have access to the memory for spilling
+ lldb::ProcessSP proc = thread.GetProcess( );
+
+ // push host data onto target
+ for ( size_t i = 0; i < args.size( ); i++ )
+ {
+ const ABI::CallArgument &arg = args[i];
+ // skip over target values
+ if ( arg.type == ABI::CallArgument::TargetValue )
+ continue;
+ // round up to 8 byte multiple
+ size_t argSize = ( arg.size | 0x7 ) + 1;
+
+ // create space on the stack for this data
+ sp -= argSize;
+
+ // write this argument onto the stack of the host process
+ proc.get( )->WriteMemory( sp, arg.data, arg.size, error );
+ if ( error.Fail( ) )
+ return false;
+
+ // update the argument with the target pointer
+ //XXX: This is a gross hack for getting around the const
+ *((size_t*)(&arg.value)) = sp;
+ }
+
+
+#if HEX_ABI_DEBUG
+ // print the original stack pointer
+ printf( "sp : %04lx \n", sp );
+#endif
+
+ // make sure number of parameters matches prototype
+ assert( prototype.getFunctionNumParams( ) == args.size( ) );
+
+ // check if this is a variable argument function
+ bool isVArg = prototype.isFunctionVarArg();
+
+ // get the register context for modifying all of the registers
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return false;
+
+ // number of arguments passed by register
+ int nRegArgs = nVArgRegParams;
+ if (! isVArg )
+ {
+ // number of arguments is limited by [R0 : R5] space
+ nRegArgs = args.size( );
+ if ( nRegArgs > 6 )
+ nRegArgs = 6;
+ }
+
+ // pass arguments that are passed via registers
+ for ( int i = 0; i < nRegArgs; i++ )
+ {
+ // get the parameter as a u32
+ uint32_t param = (uint32_t)args[i].value;
+ // write argument into register
+ if (!reg_ctx->WriteRegisterFromUnsigned( i, param ))
+ return false;
+ }
+
+ // number of arguments to spill onto stack
+ int nSpillArgs = args.size( ) - nRegArgs;
+ // make space on the stack for arguments
+ sp -= 4 * nSpillArgs;
+ // align stack on an 8 byte boundary
+ if ( sp & 7 )
+ sp -= 4;
+
+ // arguments that are passed on the stack
+ for ( size_t i = nRegArgs, offs=0; i < args.size( ); i++ )
+ {
+ // get the parameter as a u32
+ uint32_t param = (uint32_t)args[i].value;
+ // write argument to stack
+ proc->WriteMemory( sp + offs, (void*)&param, sizeof( param ), error );
+ if ( !error.Success( ) )
+ return false;
+ //
+ offs += 4;
+ }
+
+ // update registers with current function call state
+ reg_ctx->WriteRegisterFromUnsigned ( 41, pc );
+ reg_ctx->WriteRegisterFromUnsigned ( 31, ra );
+ reg_ctx->WriteRegisterFromUnsigned ( 29, sp );
+// reg_ctx->WriteRegisterFromUnsigned ( FP ??? );
+
+#if HEX_ABI_DEBUG
+ // quick and dirty stack dumper for debugging
+ for ( int i = -8; i < 8; i++ )
+ {
+ uint32_t data = 0;
+ lldb::addr_t addr = sp + i * 4;
+ proc->ReadMemory( addr, (void*)&data, sizeof( data ), error );
+ printf( "\n0x%04lx 0x%08x ", addr, data );
+ if ( i == 0 ) printf( "<<-- sp" );
+ }
+ printf( "\n" );
+#endif
+
+ return true;
+}
+
+bool
+ABISysV_hexagon::GetArgumentValues ( Thread &thread, ValueList &values ) const
+{
+ return false;
+}
+
+Error
+ABISysV_hexagon::SetReturnValueObject ( lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp )
+{
+ Error error;
+ return error;
+}
+
+ValueObjectSP
+ABISysV_hexagon::GetReturnValueObjectSimple ( Thread &thread, ClangASTType &return_clang_type ) const
+{
+ ValueObjectSP return_valobj_sp;
+ return return_valobj_sp;
+}
+
+ValueObjectSP
+ABISysV_hexagon::GetReturnValueObjectImpl ( Thread &thread, ClangASTType &return_clang_type ) const
+{
+ ValueObjectSP return_valobj_sp;
+ return return_valobj_sp;
+}
+
+// called when we are on the first instruction of a new function
+// for hexagon the return address is in RA (R31)
+bool
+ABISysV_hexagon::CreateFunctionEntryUnwindPlan ( UnwindPlan &unwind_plan )
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind(eRegisterKindGeneric);
+ unwind_plan.SetReturnAddressRegister(LLDB_REGNUM_GENERIC_RA);
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ // Our Call Frame Address is the stack pointer value
+ row->SetCFARegister(LLDB_REGNUM_GENERIC_SP);
+ row->SetCFAOffset(4);
+ row->SetOffset(0);
+
+ // The previous PC is in the LR
+ row->SetRegisterLocationToRegister(LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_RA, true);
+ unwind_plan.AppendRow(row);
+
+ unwind_plan.SetSourceName("hexagon at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
+ return true;
+}
+
+bool
+ABISysV_hexagon::CreateDefaultUnwindPlan ( UnwindPlan &unwind_plan )
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind(eRegisterKindGeneric);
+
+ uint32_t fp_reg_num = LLDB_REGNUM_GENERIC_FP;
+ uint32_t sp_reg_num = LLDB_REGNUM_GENERIC_SP;
+ uint32_t pc_reg_num = LLDB_REGNUM_GENERIC_PC;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ row->SetCFARegister(LLDB_REGNUM_GENERIC_FP);
+ row->SetCFAOffset(8);
+
+ row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num,-8, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num,-4, true);
+ row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
+
+ unwind_plan.AppendRow(row);
+ unwind_plan.SetSourceName("hexagon default unwind plan");
+ unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
+ return true;
+}
+
+/*
+ Register Usage Saved By
+
+ R0 - R5 parameters(a) -
+ R6 - R15 Scratch(b) Caller
+ R16 - R27 Scratch Callee
+ R28 Scratch(b) Caller
+ R29 - R31 Stack Frames Callee(c)
+ P3:0 Processor State Caller
+
+ a = the caller can change parameter values
+ b = R14 - R15 and R28 are used by the procedure linkage table
+ c = R29 - R31 are saved and restored by allocframe() and deallocframe()
+*/
+bool
+ABISysV_hexagon::RegisterIsVolatile ( const RegisterInfo *reg_info )
+{
+ return !RegisterIsCalleeSaved( reg_info );
+}
+
+bool
+ABISysV_hexagon::RegisterIsCalleeSaved ( const RegisterInfo *reg_info )
+{
+ int reg = ((reg_info->byte_offset) / 4);
+
+ bool save = (reg >= 16) && (reg <= 27);
+ save |= (reg >= 29) && (reg <= 32);
+
+ return save;
+}
+
+void
+ABISysV_hexagon::Initialize( void )
+{
+ PluginManager::RegisterPlugin
+ (
+ GetPluginNameStatic(),
+ "System V ABI for hexagon targets",
+ CreateInstance
+ );
+}
+
+void
+ABISysV_hexagon::Terminate( void )
+{
+ PluginManager::UnregisterPlugin( CreateInstance );
+}
+
+lldb_private::ConstString
+ABISysV_hexagon::GetPluginNameStatic()
+{
+ static ConstString g_name( "sysv-hexagon" );
+ return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ABISysV_hexagon::GetPluginName( void )
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ABISysV_hexagon::GetPluginVersion( void )
+{
+ return 1;
+}
+
+// get value object specialized to work with llvm IR types
+lldb::ValueObjectSP
+ABISysV_hexagon::GetReturnValueObjectImpl( lldb_private::Thread &thread, llvm::Type &retType ) const
+{
+ Value value;
+ ValueObjectSP vObjSP;
+
+ // get the current register context
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return vObjSP;
+
+ // for now just pop R0 to find the return value
+ const lldb_private::RegisterInfo *r0_info = reg_ctx->GetRegisterInfoAtIndex( 0 );
+ if ( r0_info == nullptr )
+ return vObjSP;
+
+ // void return type
+ if ( retType.isVoidTy( ) )
+ {
+ value.GetScalar( ) = 0;
+ }
+ // integer / pointer return type
+ else
+ if ( retType.isIntegerTy( ) || retType.isPointerTy( ) )
+ {
+ // read r0 register value
+ lldb_private::RegisterValue r0_value;
+ if ( !reg_ctx->ReadRegister( r0_info, r0_value ) )
+ return vObjSP;
+
+ // push r0 into value
+ uint32_t r0_u32 = r0_value.GetAsUInt32( );
+
+ // account for integer size
+ if ( retType.isIntegerTy() && retType.isSized() )
+ {
+ uint64_t size = retType.getScalarSizeInBits( );
+ uint64_t mask = ( 1ull << size ) - 1;
+ // mask out higher order bits then the type we expect
+ r0_u32 &= mask;
+ }
+
+ value.GetScalar( ) = r0_u32;
+ }
+ // unsupported return type
+ else
+ return vObjSP;
+
+ // pack the value into a ValueObjectSP
+ vObjSP = ValueObjectConstResult::Create
+ (
+ thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString("")
+ );
+ return vObjSP;
+}
diff --git a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h
new file mode 100644
index 000000000000..989c4a16710a
--- /dev/null
+++ b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h
@@ -0,0 +1,148 @@
+//===-- ABISysV_hexagon.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_ABISysV_hexagon_h_
+#define liblldb_ABISysV_hexagon_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+
+class ABISysV_hexagon :
+ public lldb_private::ABI
+{
+public:
+
+ ~ABISysV_hexagon( void )
+ {
+ }
+
+ virtual size_t
+ GetRedZoneSize ( void ) const;
+
+ virtual bool
+ PrepareTrivialCall ( lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ llvm::ArrayRef<lldb::addr_t> args ) const;
+
+ // special thread plan for GDB style non-jit function calls
+ virtual bool
+ PrepareTrivialCall ( lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ llvm::Type &prototype,
+ llvm::ArrayRef<ABI::CallArgument> args ) const;
+
+ virtual bool
+ GetArgumentValues ( lldb_private::Thread &thread,
+ lldb_private::ValueList &values ) const;
+
+ virtual lldb_private::Error
+ SetReturnValueObject ( lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value );
+
+protected:
+ lldb::ValueObjectSP
+ GetReturnValueObjectSimple ( lldb_private::Thread &thread,
+ lldb_private::ClangASTType &ast_type ) const;
+
+public:
+ virtual lldb::ValueObjectSP
+ GetReturnValueObjectImpl ( lldb_private::Thread &thread,
+ lldb_private::ClangASTType &type ) const;
+
+ // specialized to work with llvm IR types
+ virtual lldb::ValueObjectSP
+ GetReturnValueObjectImpl ( lldb_private::Thread &thread, llvm::Type &type ) const;
+
+ virtual bool
+ CreateFunctionEntryUnwindPlan ( lldb_private::UnwindPlan &unwind_plan );
+
+ virtual bool
+ CreateDefaultUnwindPlan ( lldb_private::UnwindPlan &unwind_plan );
+
+ virtual bool
+ RegisterIsVolatile ( const lldb_private::RegisterInfo *reg_info );
+
+ virtual bool
+ StackUsesFrames ( void )
+ {
+ return true;
+ }
+
+ virtual bool
+ CallFrameAddressIsValid ( lldb::addr_t cfa )
+ {
+ // Make sure the stack call frame addresses are 8 byte aligned
+ if (cfa & 0x07)
+ return false; // Not 8 byte aligned
+ if (cfa == 0)
+ return false; // Zero is not a valid stack address
+ return true;
+ }
+
+ virtual bool
+ CodeAddressIsValid ( lldb::addr_t pc )
+ {
+ // We have a 64 bit address space, so anything is valid as opcodes
+ // aren't fixed width...
+ return true;
+ }
+
+ virtual bool
+ FunctionCallsChangeCFA ( void )
+ {
+ return true;
+ }
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoArray ( uint32_t &count );
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize ( void );
+
+ static void
+ Terminate ( void );
+
+ static lldb::ABISP
+ CreateInstance ( const lldb_private::ArchSpec &arch );
+
+ static lldb_private::ConstString
+ GetPluginNameStatic ( void );
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName ( void );
+
+ virtual uint32_t
+ GetPluginVersion ( void );
+
+protected:
+ void
+ CreateRegisterMapIfNeeded ( void );
+
+ bool
+ RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info);
+
+private:
+ ABISysV_hexagon ( void ) : lldb_private::ABI() { } // Call CreateInstance instead.
+};
+
+#endif // liblldb_ABISysV_hexagon_h_
diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
index a8ef6a51399c..b537415bf055 100644
--- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
+++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
@@ -28,6 +28,7 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Thread.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
using namespace lldb;
@@ -251,7 +252,7 @@ static RegisterInfo g_register_infos[] =
{ "ymm15" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm15 , gcc_dwarf_ymm15 , LLDB_INVALID_REGNUM , gdb_ymm15 , LLDB_INVALID_REGNUM }, NULL, NULL}
};
-static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo);
+static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
static bool g_register_info_names_constified = false;
const lldb_private::RegisterInfo *
@@ -316,8 +317,8 @@ ABISysV_x86_64::PrepareTrivialCall (Thread &thread,
(uint64_t)func_addr,
(uint64_t)return_addr);
- for (int i = 0; i < args.size(); ++i)
- s.Printf (", arg%d = 0x%" PRIx64, i + 1, args[i]);
+ for (size_t i = 0; i < args.size(); ++i)
+ s.Printf (", arg%zd = 0x%" PRIx64, i + 1, args[i]);
s.PutCString (")");
log->PutCString(s.GetString().c_str());
}
@@ -331,11 +332,11 @@ ABISysV_x86_64::PrepareTrivialCall (Thread &thread,
if (args.size() > 6) // TODO handle more than 6 arguments
return false;
- for (int i = 0; i < args.size(); ++i)
+ for (size_t i = 0; i < args.size(); ++i)
{
reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i);
if (log)
- log->Printf("About to write arg%d (0x%" PRIx64 ") into %s", i + 1, args[i], reg_info->name);
+ log->Printf("About to write arg%zd (0x%" PRIx64 ") into %s", i + 1, args[i], reg_info->name);
if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
return false;
}
@@ -562,7 +563,13 @@ ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueOb
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("rax", 0);
DataExtractor data;
- size_t num_bytes = new_value_sp->GetData(data);
+ Error data_error;
+ size_t num_bytes = new_value_sp->GetData(data, data_error);
+ if (data_error.Fail())
+ {
+ error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString());
+ return error;
+ }
lldb::offset_t offset = 0;
if (num_bytes <= 8)
{
@@ -589,8 +596,14 @@ ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueOb
const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0);
RegisterValue xmm0_value;
DataExtractor data;
- size_t num_bytes = new_value_sp->GetData(data);
-
+ Error data_error;
+ size_t num_bytes = new_value_sp->GetData(data, data_error);
+ if (data_error.Fail())
+ {
+ error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString());
+ return error;
+ }
+
unsigned char buffer[16];
ByteOrder byte_order = data.GetByteOrder();
diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
index e9b8a9f573a3..c14371d0589c 100644
--- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
+++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
@@ -10,10 +10,10 @@
#include "DisassemblerLLVMC.h"
#include "llvm-c/Disassembler.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler.h"
+#include "llvm/MC/MCExternalSymbolizer.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCInstrInfo.h"
@@ -48,7 +48,7 @@ class InstructionLLVMC : public lldb_private::Instruction
{
public:
InstructionLLVMC (DisassemblerLLVMC &disasm,
- const lldb_private::Address &address,
+ const lldb_private::Address &address,
AddressClass addr_class) :
Instruction (address, addr_class),
m_disasm_sp (disasm.shared_from_this()),
@@ -57,12 +57,12 @@ public:
m_using_file_addr (false)
{
}
-
+
virtual
~InstructionLLVMC ()
{
}
-
+
virtual bool
DoesBranch ()
{
@@ -99,7 +99,7 @@ public:
}
return m_does_branch == eLazyBoolYes;
}
-
+
DisassemblerLLVMC::LLVMCDisassembler *
GetDisasmToUse (bool &is_alternate_isa)
{
@@ -108,7 +108,7 @@ public:
if (llvm_disasm.m_alternate_disasm_ap.get() != NULL)
{
const AddressClass address_class = GetAddressClass ();
-
+
if (address_class == eAddressClassCodeAlternateISA)
{
is_alternate_isa = true;
@@ -117,7 +117,7 @@ public:
}
return llvm_disasm.m_disasm_ap.get();
}
-
+
virtual size_t
Decode (const lldb_private::Disassembler &disassembler,
const lldb_private::DataExtractor &data,
@@ -129,7 +129,7 @@ public:
DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC();
const ArchSpec &arch = llvm_disasm.GetArchitecture();
const lldb::ByteOrder byte_order = data.GetByteOrder();
-
+
const uint32_t min_op_byte_size = arch.GetMinimumOpcodeByteSize();
const uint32_t max_op_byte_size = arch.GetMaximumOpcodeByteSize();
if (min_op_byte_size == max_op_byte_size)
@@ -170,7 +170,7 @@ public:
{
bool is_alternate_isa = false;
DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
-
+
const llvm::Triple::ArchType machine = arch.GetMachine();
if (machine == llvm::Triple::arm || machine == llvm::Triple::thumb)
{
@@ -204,7 +204,7 @@ public:
const size_t opcode_data_len = data.BytesLeft(data_offset);
const addr_t pc = m_address.GetFileAddress();
llvm::MCInst inst;
-
+
llvm_disasm.Lock(this, NULL);
const size_t inst_size = mc_disasm_ptr->GetMCInst(opcode_data,
opcode_data_len,
@@ -222,7 +222,7 @@ public:
}
return m_opcode.GetByteSize();
}
-
+
void
AppendComment (std::string &description)
{
@@ -234,7 +234,7 @@ public:
m_comment.append(description);
}
}
-
+
virtual void
CalculateMnemonicOperandsAndComment (const lldb_private::ExecutionContext *exe_ctx)
{
@@ -244,19 +244,19 @@ public:
if (m_opcode.GetData(data))
{
char out_string[512];
-
+
DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC();
DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr;
-
+
if (address_class == eAddressClassCodeAlternateISA)
mc_disasm_ptr = llvm_disasm.m_alternate_disasm_ap.get();
else
mc_disasm_ptr = llvm_disasm.m_disasm_ap.get();
-
+
lldb::addr_t pc = m_address.GetFileAddress();
m_using_file_addr = true;
-
+
const bool data_from_file = GetDisassemblerLLVMC().m_data_from_file;
bool use_hex_immediates = true;
Disassembler::HexImmediateStyle hex_style = Disassembler::eHexStyleC;
@@ -280,9 +280,9 @@ public:
}
}
}
-
+
llvm_disasm.Lock(this, exe_ctx);
-
+
const uint8_t *opcode_data = data.GetDataStart();
const size_t opcode_data_len = data.GetByteSize();
llvm::MCInst inst;
@@ -298,7 +298,7 @@ public:
}
llvm_disasm.Unlock();
-
+
if (inst_size == 0)
{
m_comment.assign ("unknown opcode");
@@ -371,11 +371,11 @@ public:
}
}
-
+
static RegularExpression s_regex("[ \t]*([^ ^\t]+)[ \t]*([^ ^\t].*)?", REG_EXTENDED);
-
+
RegularExpression::Match matches(3);
-
+
if (s_regex.Execute(out_string, &matches))
{
matches.GetMatchAtIndex(out_string, 1, m_opcode_name);
@@ -383,13 +383,13 @@ public:
}
}
}
-
+
bool
IsValid () const
{
return m_is_valid;
}
-
+
bool
UsingFileAddress() const
{
@@ -400,14 +400,14 @@ public:
{
return m_opcode.GetByteSize();
}
-
+
DisassemblerLLVMC &
GetDisassemblerLLVMC ()
{
return *(DisassemblerLLVMC *)m_disasm_sp.get();
}
protected:
-
+
DisassemblerSP m_disasm_sp; // for ownership
LazyBool m_does_branch;
bool m_is_valid;
@@ -426,15 +426,15 @@ DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, uns
m_is_valid = false;
return;
}
-
+
m_instr_info_ap.reset(curr_target->createMCInstrInfo());
m_reg_info_ap.reset (curr_target->createMCRegInfo(triple));
-
+
std::string features_str;
m_subtarget_info_ap.reset(curr_target->createMCSubtargetInfo(triple, "",
features_str));
-
+
std::unique_ptr<llvm::MCRegisterInfo> reg_info(curr_target->createMCRegInfo(triple));
m_asm_info_ap.reset(curr_target->createMCAsmInfo(*reg_info, triple));
@@ -443,24 +443,25 @@ DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, uns
m_is_valid = false;
return;
}
-
+
m_context_ap.reset(new llvm::MCContext(m_asm_info_ap.get(), m_reg_info_ap.get(), 0));
-
- m_disasm_ap.reset(curr_target->createMCDisassembler(*m_subtarget_info_ap.get()));
+
+ m_disasm_ap.reset(curr_target->createMCDisassembler(*m_subtarget_info_ap.get(), *m_context_ap.get()));
if (m_disasm_ap.get() && m_context_ap.get())
{
- llvm::OwningPtr<llvm::MCRelocationInfo> RelInfo(curr_target->createMCRelocationInfo(triple, *m_context_ap.get()));
+ std::unique_ptr<llvm::MCRelocationInfo> RelInfo(curr_target->createMCRelocationInfo(triple, *m_context_ap.get()));
if (!RelInfo)
{
m_is_valid = false;
return;
}
- m_disasm_ap->setupForSymbolicDisassembly(NULL,
- DisassemblerLLVMC::SymbolLookupCallback,
- (void *) &owner,
- m_context_ap.get(),
- RelInfo);
-
+ std::unique_ptr<llvm::MCSymbolizer> symbolizer_up(curr_target->createMCSymbolizer(triple, NULL,
+ DisassemblerLLVMC::SymbolLookupCallback,
+ (void *) &owner,
+ m_context_ap.get(), RelInfo.release()));
+ m_disasm_ap->setSymbolizer(std::move(symbolizer_up));
+
+
unsigned asm_printer_variant;
if (flavor == ~0U)
asm_printer_variant = m_asm_info_ap->getAssemblerDialect();
@@ -468,7 +469,7 @@ DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, uns
{
asm_printer_variant = flavor;
}
-
+
m_instr_printer_ap.reset(curr_target->createMCInstPrinter(asm_printer_variant,
*m_asm_info_ap.get(),
*m_instr_info_ap.get(),
@@ -497,7 +498,7 @@ namespace {
public:
LLDBDisasmMemoryObject(const uint8_t *bytes, uint64_t size, uint64_t basePC) :
m_bytes(bytes), m_size(size), m_base_PC(basePC) {}
-
+
uint64_t getBase() const { return m_base_PC; }
uint64_t getExtent() const { return m_size; }
@@ -545,7 +546,7 @@ DisassemblerLLVMC::LLVMCDisassembler::PrintMCInst (llvm::MCInst &mc_inst,
const size_t output_size = std::min(dst_len - 1, inst_string.size());
std::memcpy(dst, inst_string.data(), output_size);
dst[output_size] = '\0';
-
+
return output_size;
}
@@ -572,7 +573,7 @@ DisassemblerLLVMC::FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, c
llvm::Triple triple = arch.GetTriple();
if (flavor == NULL || strcmp (flavor, "default") == 0)
return true;
-
+
if (triple.getArch() == llvm::Triple::x86 || triple.getArch() == llvm::Triple::x86_64)
{
if (strcmp (flavor, "intel") == 0 || strcmp (flavor, "att") == 0)
@@ -583,7 +584,7 @@ DisassemblerLLVMC::FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, c
else
return false;
}
-
+
Disassembler *
DisassemblerLLVMC::CreateInstance (const ArchSpec &arch, const char *flavor)
@@ -591,7 +592,7 @@ DisassemblerLLVMC::CreateInstance (const ArchSpec &arch, const char *flavor)
if (arch.GetTriple().getArch() != llvm::Triple::UnknownArch)
{
std::unique_ptr<DisassemblerLLVMC> disasm_ap (new DisassemblerLLVMC(arch, flavor));
-
+
if (disasm_ap.get() && disasm_ap->IsValid())
return disasm_ap.release();
}
@@ -608,10 +609,10 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s
{
m_flavor.assign("default");
}
-
+
const char *triple = arch.GetTriple().getTriple().c_str();
unsigned flavor = ~0U;
-
+
// So far the only supported flavor is "intel" on x86. The base class will set this
// correctly coming in.
if (arch.GetTriple().getArch() == llvm::Triple::x86
@@ -626,7 +627,7 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s
flavor = 0;
}
}
-
+
ArchSpec thumb_arch(arch);
if (arch.GetTriple().getArch() == llvm::Triple::arm)
{
@@ -643,15 +644,15 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s
}
thumb_arch.GetTriple().setArchName(llvm::StringRef(thumb_arch_name.c_str()));
}
-
- // Cortex-M3 devices (e.g. armv7m) can only execute thumb (T2) instructions,
+
+ // Cortex-M3 devices (e.g. armv7m) can only execute thumb (T2) instructions,
// so hardcode the primary disassembler to thumb mode. Same for Cortex-M4 (armv7em).
//
// Handle the Cortex-M0 (armv6m) the same; the ISA is a subset of the T and T32
- // instructions defined in ARMv7-A.
+ // instructions defined in ARMv7-A.
if (arch.GetTriple().getArch() == llvm::Triple::arm
- && (arch.GetCore() == ArchSpec::Core::eCore_arm_armv7m
+ && (arch.GetCore() == ArchSpec::Core::eCore_arm_armv7m
|| arch.GetCore() == ArchSpec::Core::eCore_arm_armv7em
|| arch.GetCore() == ArchSpec::Core::eCore_arm_armv6m))
{
@@ -693,33 +694,33 @@ DisassemblerLLVMC::DecodeInstructions (const Address &base_addr,
{
if (!append)
m_instruction_list.Clear();
-
+
if (!IsValid())
return 0;
-
+
m_data_from_file = data_from_file;
uint32_t data_cursor = data_offset;
const size_t data_byte_size = data.GetByteSize();
uint32_t instructions_parsed = 0;
Address inst_addr(base_addr);
-
+
while (data_cursor < data_byte_size && instructions_parsed < num_instructions)
{
-
+
AddressClass address_class = eAddressClassCode;
-
+
if (m_alternate_disasm_ap.get() != NULL)
address_class = inst_addr.GetAddressClass ();
-
+
InstructionSP inst_sp(new InstructionLLVMC(*this,
- inst_addr,
+ inst_addr,
address_class));
-
+
if (!inst_sp)
break;
-
+
uint32_t inst_size = inst_sp->Decode(*this, data, data_cursor);
-
+
if (inst_size == 0)
break;
@@ -728,7 +729,7 @@ DisassemblerLLVMC::DecodeInstructions (const Address &base_addr,
inst_addr.Slide(inst_size);
instructions_parsed++;
}
-
+
return data_cursor - data_offset;
}
@@ -736,9 +737,9 @@ void
DisassemblerLLVMC::Initialize()
{
PluginManager::RegisterPlugin (GetPluginNameStatic(),
- "Disassembler that uses LLVM MC to disassemble i386, x86_64 and ARM.",
+ "Disassembler that uses LLVM MC to disassemble i386, x86_64, ARM, and ARM64.",
CreateInstance);
-
+
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
@@ -810,7 +811,7 @@ const char *DisassemblerLLVMC::SymbolLookup (uint64_t value,
if (*type_ptr)
{
if (m_exe_ctx && m_inst)
- {
+ {
//std::string remove_this_prior_to_checkin;
Target *target = m_exe_ctx ? m_exe_ctx->GetTargetPtr() : NULL;
Address value_so_addr;
@@ -824,16 +825,16 @@ const char *DisassemblerLLVMC::SymbolLookup (uint64_t value,
{
target->GetSectionLoadList().ResolveLoadAddress(value, value_so_addr);
}
-
+
if (value_so_addr.IsValid() && value_so_addr.GetSection())
{
StreamString ss;
-
+
value_so_addr.Dump (&ss,
target,
Address::DumpStyleResolvedDescriptionNoModule,
Address::DumpStyleSectionNameOffset);
-
+
if (!ss.GetString().empty())
{
m_inst->AppendComment(ss.GetString());
@@ -861,4 +862,3 @@ DisassemblerLLVMC::GetPluginVersion()
{
return 1;
}
-
diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
index c567791866d5..6ab9e9ae2625 100644
--- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
+++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
@@ -42,9 +42,9 @@ class DisassemblerLLVMC : public lldb_private::Disassembler
{
public:
LLVMCDisassembler (const char *triple, unsigned flavor, DisassemblerLLVMC &owner);
-
+
~LLVMCDisassembler();
-
+
uint64_t GetMCInst (const uint8_t *opcode_data, size_t opcode_data_len, lldb::addr_t pc, llvm::MCInst &mc_inst);
uint64_t PrintMCInst (llvm::MCInst &mc_inst, char *output_buffer, size_t out_buffer_len);
void SetStyle (bool use_hex_immed, HexImmediateStyle hex_style);
@@ -53,7 +53,7 @@ class DisassemblerLLVMC : public lldb_private::Disassembler
{
return m_is_valid;
}
-
+
private:
bool m_is_valid;
std::unique_ptr<llvm::MCContext> m_context_ap;
@@ -71,21 +71,21 @@ public:
//------------------------------------------------------------------
static void
Initialize();
-
+
static void
Terminate();
-
+
static lldb_private::ConstString
GetPluginNameStatic();
-
+
static lldb_private::Disassembler *
CreateInstance(const lldb_private::ArchSpec &arch, const char *flavor);
-
+
DisassemblerLLVMC(const lldb_private::ArchSpec &arch, const char *flavor /* = NULL */);
-
+
virtual
~DisassemblerLLVMC();
-
+
virtual size_t
DecodeInstructions (const lldb_private::Address &base_addr,
const lldb_private::DataExtractor& data,
@@ -93,72 +93,72 @@ public:
size_t num_instructions,
bool append,
bool data_from_file);
-
+
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
virtual lldb_private::ConstString
GetPluginName();
-
+
virtual uint32_t
GetPluginVersion();
-
+
protected:
friend class InstructionLLVMC;
-
+
virtual bool
FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, const char *flavor);
-
+
bool
IsValid()
{
return (m_disasm_ap.get() != NULL && m_disasm_ap->IsValid());
}
-
+
int OpInfo(uint64_t PC,
uint64_t Offset,
uint64_t Size,
int TagType,
void *TagBug);
-
+
const char *SymbolLookup (uint64_t ReferenceValue,
uint64_t *ReferenceType,
uint64_t ReferencePC,
const char **ReferenceName);
-
+
static int OpInfoCallback (void *DisInfo,
uint64_t PC,
uint64_t Offset,
uint64_t Size,
int TagType,
void *TagBug);
-
+
static const char *SymbolLookupCallback(void *DisInfo,
uint64_t ReferenceValue,
uint64_t *ReferenceType,
uint64_t ReferencePC,
const char **ReferenceName);
-
- void Lock(InstructionLLVMC *inst,
+
+ void Lock(InstructionLLVMC *inst,
const lldb_private::ExecutionContext *exe_ctx)
{
m_mutex.Lock();
m_inst = inst;
m_exe_ctx = exe_ctx;
}
-
+
void Unlock()
{
m_inst = NULL;
m_exe_ctx = NULL;
m_mutex.Unlock();
}
-
+
const lldb_private::ExecutionContext *m_exe_ctx;
InstructionLLVMC *m_inst;
lldb_private::Mutex m_mutex;
bool m_data_from_file;
-
+
std::unique_ptr<LLVMCDisassembler> m_disasm_ap;
std::unique_ptr<LLVMCDisassembler> m_alternate_disasm_ap;
};
diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
new file mode 100644
index 000000000000..c79d96abafa2
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
@@ -0,0 +1,727 @@
+//===-- DynamicLoaderHexagon.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+
+#include "DynamicLoaderHexagonDYLD.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Aidan 21/05/2014
+//
+// Notes about hexagon dynamic loading:
+//
+// When we connect to a target we find the dyld breakpoint address. We put a
+// breakpoint there with a callback 'RendezvousBreakpointHit()'.
+//
+// It is possible to find the dyld structure address from the ELF symbol table,
+// but in the case of the simulator it has not been initialized before the
+// target calls dlinit().
+//
+// We can only safely parse the dyld structure after we hit the dyld breakpoint
+// since at that time we know dlinit() must have been called.
+//
+
+// Find the load address of a symbol
+static lldb::addr_t findSymbolAddress( Process *proc, ConstString findName )
+{
+ assert( proc != nullptr );
+
+ ModuleSP module = proc->GetTarget().GetExecutableModule();
+ assert( module.get() != nullptr );
+
+ ObjectFile *exe = module->GetObjectFile();
+ assert( exe != nullptr );
+
+ lldb_private::Symtab *symtab = exe->GetSymtab( );
+ assert( symtab != nullptr );
+
+ for ( size_t i = 0; i < symtab->GetNumSymbols( ); i++ )
+ {
+ const Symbol* sym = symtab->SymbolAtIndex( i );
+ assert( sym != nullptr );
+ const ConstString &symName = sym->GetName( );
+
+ if ( ConstString::Compare( findName, symName ) == 0 )
+ {
+ Address addr = sym->GetAddress( );
+ return addr.GetLoadAddress( & proc->GetTarget() );
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+void
+DynamicLoaderHexagonDYLD::Initialize()
+{
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+DynamicLoaderHexagonDYLD::Terminate()
+{
+}
+
+lldb_private::ConstString
+DynamicLoaderHexagonDYLD::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+lldb_private::ConstString
+DynamicLoaderHexagonDYLD::GetPluginNameStatic()
+{
+ static ConstString g_name("hexagon-dyld");
+ return g_name;
+}
+
+const char *
+DynamicLoaderHexagonDYLD::GetPluginDescriptionStatic()
+{
+ return "Dynamic loader plug-in that watches for shared library "
+ "loads/unloads in Hexagon processes.";
+}
+
+void
+DynamicLoaderHexagonDYLD::GetPluginCommandHelp(const char *command, Stream *strm)
+{
+}
+
+uint32_t
+DynamicLoaderHexagonDYLD::GetPluginVersion()
+{
+ return 1;
+}
+
+DynamicLoader *
+DynamicLoaderHexagonDYLD::CreateInstance(Process *process, bool force)
+{
+ bool create = force;
+ if (!create)
+ {
+ const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple();
+ if (triple_ref.getArch() == llvm::Triple::hexagon)
+ create = true;
+ }
+
+ if (create)
+ return new DynamicLoaderHexagonDYLD(process);
+ return NULL;
+}
+
+DynamicLoaderHexagonDYLD::DynamicLoaderHexagonDYLD(Process *process)
+ : DynamicLoader(process)
+ , m_rendezvous (process)
+ , m_load_offset(LLDB_INVALID_ADDRESS)
+ , m_entry_point(LLDB_INVALID_ADDRESS)
+ , m_dyld_bid (LLDB_INVALID_BREAK_ID)
+{
+}
+
+DynamicLoaderHexagonDYLD::~DynamicLoaderHexagonDYLD()
+{
+ if (m_dyld_bid != LLDB_INVALID_BREAK_ID)
+ {
+ m_process->GetTarget().RemoveBreakpointByID (m_dyld_bid);
+ m_dyld_bid = LLDB_INVALID_BREAK_ID;
+ }
+}
+
+void
+DynamicLoaderHexagonDYLD::DidAttach()
+{
+ ModuleSP executable;
+ addr_t load_offset;
+
+ executable = GetTargetExecutable();
+
+ // Find the difference between the desired load address in the elf file
+ // and the real load address in memory
+ load_offset = ComputeLoadOffset();
+
+ // Check that there is a valid executable
+ if ( executable.get( ) == nullptr )
+ return;
+
+ // Disable JIT for hexagon targets because its not supported
+ m_process->SetCanJIT(false);
+
+ // Add the current executable to the module list
+ ModuleList module_list;
+ module_list.Append(executable);
+
+ // Map the loaded sections of this executable
+ if ( load_offset != LLDB_INVALID_ADDRESS )
+ UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset);
+
+ // AD: confirm this?
+ // Load into LLDB all of the currently loaded executables in the stub
+ LoadAllCurrentModules();
+
+ // AD: confirm this?
+ // Callback for the target to give it the loaded module list
+ m_process->GetTarget().ModulesDidLoad(module_list);
+
+ // Try to set a breakpoint at the rendezvous breakpoint.
+ // DidLaunch uses ProbeEntry() instead. That sets a breakpoint,
+ // at the dyld breakpoint address, with a callback so that when hit,
+ // the dyld structure can be parsed.
+ if (! SetRendezvousBreakpoint() )
+ {
+ // fail
+ }
+}
+
+void
+DynamicLoaderHexagonDYLD::DidLaunch()
+{
+}
+
+/// Checks to see if the target module has changed, updates the target
+/// accordingly and returns the target executable module.
+ModuleSP
+DynamicLoaderHexagonDYLD::GetTargetExecutable()
+{
+ Target &target = m_process->GetTarget();
+ ModuleSP executable = target.GetExecutableModule();
+
+ // There is no executable
+ if (! executable.get())
+ return executable;
+
+ // The target executable file does not exits
+ if (! executable->GetFileSpec().Exists())
+ return executable;
+
+ // Prep module for loading
+ ModuleSpec module_spec(executable->GetFileSpec(), executable->GetArchitecture());
+ ModuleSP module_sp (new Module (module_spec));
+
+ // Check if the executable has changed and set it to the target executable if they differ.
+ if (module_sp.get() && module_sp->GetUUID().IsValid() && executable->GetUUID().IsValid())
+ {
+ // if the executable has changed ??
+ if (module_sp->GetUUID() != executable->GetUUID())
+ executable.reset();
+ }
+ else if (executable->FileHasChanged())
+ executable.reset();
+
+ if ( executable.get( ) )
+ return executable;
+
+ // TODO: What case is this code used?
+ executable = target.GetSharedModule(module_spec);
+ if (executable.get() != target.GetExecutableModulePointer())
+ {
+ // Don't load dependent images since we are in dyld where we will know
+ // and find out about all images that are loaded
+ const bool get_dependent_images = false;
+ target.SetExecutableModule(executable, get_dependent_images);
+ }
+
+ return executable;
+}
+
+Error
+DynamicLoaderHexagonDYLD::ExecutePluginCommand(Args &command, Stream *strm)
+{
+ return Error();
+}
+
+Log *
+DynamicLoaderHexagonDYLD::EnablePluginLogging(Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+//AD: Needs to be updated?
+Error
+DynamicLoaderHexagonDYLD::CanLoadImage()
+{
+ return Error();
+}
+
+void
+DynamicLoaderHexagonDYLD::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, addr_t base_addr)
+{
+ Target &target = m_process->GetTarget();
+ const SectionList *sections = GetSectionListFromModule(module);
+
+ assert(sections && "SectionList missing from loaded module.");
+
+ m_loaded_modules[module] = link_map_addr;
+
+ const size_t num_sections = sections->GetSize();
+
+ for (unsigned i = 0; i < num_sections; ++i)
+ {
+ SectionSP section_sp (sections->GetSectionAtIndex(i));
+ lldb::addr_t new_load_addr = section_sp->GetFileAddress() + base_addr;
+
+ // AD: 02/05/14
+ // since our memory map starts from address 0, we must not ignore
+ // sections that load to address 0. This violates the reference
+ // ELF spec, however is used for Hexagon.
+
+ // If the file address of the section is zero then this is not an
+ // allocatable/loadable section (property of ELF sh_addr). Skip it.
+// if (new_load_addr == base_addr)
+// continue;
+
+ target.SetSectionLoadAddress(section_sp, new_load_addr);
+ }
+}
+
+/// Removes the loaded sections from the target in @p module.
+///
+/// @param module The module to traverse.
+void
+DynamicLoaderHexagonDYLD::UnloadSections(const ModuleSP module)
+{
+ Target &target = m_process->GetTarget();
+ const SectionList *sections = GetSectionListFromModule(module);
+
+ assert(sections && "SectionList missing from unloaded module.");
+
+ m_loaded_modules.erase(module);
+
+ const size_t num_sections = sections->GetSize();
+ for (size_t i = 0; i < num_sections; ++i)
+ {
+ SectionSP section_sp (sections->GetSectionAtIndex(i));
+ target.SetSectionUnloaded(section_sp);
+ }
+}
+
+// Place a breakpoint on <_rtld_debug_state>
+bool
+DynamicLoaderHexagonDYLD::SetRendezvousBreakpoint()
+{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
+ // This is the original code, which want to look in the rendezvous structure
+ // to find the breakpoint address. Its backwards for us, since we can easily
+ // find the breakpoint address, since it is exported in our executable.
+ // We however know that we cant read the Rendezvous structure until we have hit
+ // the breakpoint once.
+ const ConstString dyldBpName( "_rtld_debug_state" );
+ addr_t break_addr = findSymbolAddress( m_process, dyldBpName );
+
+ Target &target = m_process->GetTarget();
+
+ // Do not try to set the breakpoint if we don't know where to put it
+ if ( break_addr == LLDB_INVALID_ADDRESS )
+ {
+ if ( log )
+ log->Printf( "Unable to locate _rtld_debug_state breakpoint address" );
+
+ return false;
+ }
+
+ // Save the address of the rendezvous structure
+ m_rendezvous.SetBreakAddress( break_addr );
+
+ // If we haven't set the breakpoint before then set it
+ if (m_dyld_bid == LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *dyld_break = target.CreateBreakpoint (break_addr, true, false).get();
+ dyld_break->SetCallback(RendezvousBreakpointHit, this, true);
+ dyld_break->SetBreakpointKind ("shared-library-event");
+ m_dyld_bid = dyld_break->GetID();
+
+ // Make sure our breakpoint is at the right address.
+ assert
+ (
+ target.GetBreakpointByID(m_dyld_bid)->
+ FindLocationByAddress(break_addr)->
+ GetBreakpoint().GetID()
+ == m_dyld_bid
+ );
+
+ if ( log && dyld_break == nullptr )
+ log->Printf( "Failed to create _rtld_debug_state breakpoint" );
+
+ // check we have successfully set bp
+ return (dyld_break != nullptr);
+ }
+ else
+ // rendezvous already set
+ return true;
+}
+
+// We have just hit our breakpoint at <_rtld_debug_state>
+bool
+DynamicLoaderHexagonDYLD::RendezvousBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ user_id_t break_id,
+ user_id_t break_loc_id)
+{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
+ if ( log )
+ log->Printf( "Rendezvous breakpoint hit!" );
+
+ DynamicLoaderHexagonDYLD* dyld_instance = nullptr;
+ dyld_instance = static_cast<DynamicLoaderHexagonDYLD*>(baton);
+
+ // if the dyld_instance is still not valid then
+ // try to locate it on the symbol table
+ if ( !dyld_instance->m_rendezvous.IsValid( ) )
+ {
+ Process *proc = dyld_instance->m_process;
+
+ const ConstString dyldStructName( "_rtld_debug" );
+ addr_t structAddr = findSymbolAddress( proc, dyldStructName );
+
+ if ( structAddr != LLDB_INVALID_ADDRESS )
+ {
+ dyld_instance->m_rendezvous.SetRendezvousAddress( structAddr );
+
+ if ( log )
+ log->Printf( "Found _rtld_debug structure @ 0x%08lx", structAddr );
+ }
+ else
+ {
+ if ( log )
+ log->Printf( "Unable to resolve the _rtld_debug structure" );
+ }
+ }
+
+ dyld_instance->RefreshModules();
+
+ // Return true to stop the target, false to just let the target run.
+ return dyld_instance->GetStopWhenImagesChange();
+}
+
+/// Helper method for RendezvousBreakpointHit. Updates LLDB's current set
+/// of loaded modules.
+void
+DynamicLoaderHexagonDYLD::RefreshModules()
+{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
+ if (!m_rendezvous.Resolve())
+ return;
+
+ HexagonDYLDRendezvous::iterator I;
+ HexagonDYLDRendezvous::iterator E;
+
+ ModuleList &loaded_modules = m_process->GetTarget().GetImages();
+
+ if (m_rendezvous.ModulesDidLoad())
+ {
+ ModuleList new_modules;
+
+ E = m_rendezvous.loaded_end();
+ for (I = m_rendezvous.loaded_begin(); I != E; ++I)
+ {
+ FileSpec file(I->path.c_str(), true);
+ ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr);
+ if (module_sp.get())
+ {
+ loaded_modules.AppendIfNeeded( module_sp );
+ new_modules.Append(module_sp);
+ }
+
+ if (log)
+ {
+ log->Printf( "Target is loading '%s'", I->path.c_str() );
+ if (! module_sp.get() )
+ log->Printf( "LLDB failed to load '%s'", I->path.c_str() );
+ else
+ log->Printf( "LLDB successfully loaded '%s'", I->path.c_str() );
+ }
+
+ }
+ m_process->GetTarget().ModulesDidLoad(new_modules);
+ }
+
+ if (m_rendezvous.ModulesDidUnload())
+ {
+ ModuleList old_modules;
+
+ E = m_rendezvous.unloaded_end();
+ for (I = m_rendezvous.unloaded_begin(); I != E; ++I)
+ {
+ FileSpec file(I->path.c_str(), true);
+ ModuleSpec module_spec(file);
+ ModuleSP module_sp = loaded_modules.FindFirstModule (module_spec);
+
+ if (module_sp.get())
+ {
+ old_modules.Append(module_sp);
+ UnloadSections(module_sp);
+ }
+
+ if (log)
+ log->Printf( "Target is unloading '%s'", I->path.c_str() );
+
+ }
+ loaded_modules.Remove(old_modules);
+ m_process->GetTarget().ModulesDidUnload(old_modules, false);
+ }
+}
+
+//AD: This is very different to the Static Loader code.
+// It may be wise to look over this and its relation to stack
+// unwinding.
+ThreadPlanSP
+DynamicLoaderHexagonDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop)
+{
+ ThreadPlanSP thread_plan_sp;
+
+ StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
+ const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol);
+ Symbol *sym = context.symbol;
+
+ if (sym == NULL || !sym->IsTrampoline())
+ return thread_plan_sp;
+
+ const ConstString &sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled);
+ if (!sym_name)
+ return thread_plan_sp;
+
+ SymbolContextList target_symbols;
+ Target &target = thread.GetProcess()->GetTarget();
+ const ModuleList &images = target.GetImages();
+
+ images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols);
+ size_t num_targets = target_symbols.GetSize();
+ if (!num_targets)
+ return thread_plan_sp;
+
+ typedef std::vector<lldb::addr_t> AddressVector;
+ AddressVector addrs;
+ for (size_t i = 0; i < num_targets; ++i)
+ {
+ SymbolContext context;
+ AddressRange range;
+ if (target_symbols.GetContextAtIndex(i, context))
+ {
+ context.GetAddressRange(eSymbolContextEverything, 0, false, range);
+ lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target);
+ if (addr != LLDB_INVALID_ADDRESS)
+ addrs.push_back(addr);
+ }
+ }
+
+ if (addrs.size() > 0)
+ {
+ AddressVector::iterator start = addrs.begin();
+ AddressVector::iterator end = addrs.end();
+
+ std::sort(start, end);
+ addrs.erase(std::unique(start, end), end);
+ thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop));
+ }
+
+ return thread_plan_sp;
+}
+
+/// Helper for the entry breakpoint callback. Resolves the load addresses
+/// of all dependent modules.
+void
+DynamicLoaderHexagonDYLD::LoadAllCurrentModules()
+{
+ HexagonDYLDRendezvous::iterator I;
+ HexagonDYLDRendezvous::iterator E;
+ ModuleList module_list;
+
+ if (!m_rendezvous.Resolve())
+ {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ if (log)
+ log->Printf("DynamicLoaderHexagonDYLD::%s unable to resolve rendezvous address", __FUNCTION__);
+ return;
+ }
+
+ // The rendezvous class doesn't enumerate the main module, so track
+ // that ourselves here.
+ ModuleSP executable = GetTargetExecutable();
+ m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress();
+
+
+ for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
+ {
+ const char *module_path = I->path.c_str();
+ FileSpec file(module_path, false);
+ ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr);
+ if (module_sp.get())
+ {
+ module_list.Append(module_sp);
+ }
+ else
+ {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ if (log)
+ log->Printf("DynamicLoaderHexagonDYLD::%s failed loading module %s at 0x%" PRIx64,
+ __FUNCTION__, module_path, I->base_addr);
+ }
+ }
+
+ m_process->GetTarget().ModulesDidLoad(module_list);
+}
+
+/// Helper for the entry breakpoint callback. Resolves the load addresses
+/// of all dependent modules.
+ModuleSP
+DynamicLoaderHexagonDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, addr_t base_addr)
+{
+ Target &target = m_process->GetTarget();
+ ModuleList &modules = target.GetImages();
+ ModuleSP module_sp;
+
+ ModuleSpec module_spec (file, target.GetArchitecture());
+
+ // check if module is currently loaded
+ if ((module_sp = modules.FindFirstModule (module_spec)))
+ {
+ UpdateLoadedSections(module_sp, link_map_addr, base_addr);
+ }
+ // try to load this module from disk
+ else if ((module_sp = target.GetSharedModule(module_spec)))
+ {
+ UpdateLoadedSections(module_sp, link_map_addr, base_addr);
+ }
+
+ return module_sp;
+}
+
+/// Computes a value for m_load_offset returning the computed address on
+/// success and LLDB_INVALID_ADDRESS on failure.
+addr_t
+DynamicLoaderHexagonDYLD::ComputeLoadOffset()
+{
+ // Here we could send a GDB packet to know the load offset
+ //
+ // send: $qOffsets#4b
+ // get: Text=0;Data=0;Bss=0
+ //
+ // Currently qOffsets is not supported by pluginProcessGDBRemote
+ //
+ return 0;
+}
+
+// Here we must try to read the entry point directly from
+// the elf header. This is possible if the process is not
+// relocatable or dynamically linked.
+//
+// an alternative is to look at the PC if we can be sure
+// that we have connected when the process is at the entry point.
+// I dont think that is reliable for us.
+addr_t
+DynamicLoaderHexagonDYLD::GetEntryPoint()
+{
+ if (m_entry_point != LLDB_INVALID_ADDRESS)
+ return m_entry_point;
+ // check we have a valid process
+ if ( m_process == nullptr )
+ return LLDB_INVALID_ADDRESS;
+ // Get the current executable module
+ Module & module = *( m_process->GetTarget( ).GetExecutableModule( ).get( ) );
+ // Get the object file (elf file) for this module
+ lldb_private::ObjectFile &object = *( module.GetObjectFile( ) );
+ // Check if the file is executable (ie, not shared object or relocatable)
+ if ( object.IsExecutable() )
+ {
+ // Get the entry point address for this object
+ lldb_private::Address entry = object.GetEntryPointAddress( );
+ // Return the entry point address
+ return entry.GetFileAddress( );
+ }
+ // No idea so back out
+ return LLDB_INVALID_ADDRESS;
+}
+
+const SectionList *
+DynamicLoaderHexagonDYLD::GetSectionListFromModule(const ModuleSP module) const
+{
+ SectionList *sections = nullptr;
+ if (module.get())
+ {
+ ObjectFile *obj_file = module->GetObjectFile();
+ if (obj_file)
+ {
+ sections = obj_file->GetSectionList();
+ }
+ }
+ return sections;
+}
+
+static int ReadInt(Process *process, addr_t addr)
+{
+ Error error;
+ int value = (int)process->ReadUnsignedIntegerFromMemory(addr, sizeof(uint32_t), 0, error);
+ if (error.Fail())
+ return -1;
+ else
+ return value;
+}
+
+lldb::addr_t
+DynamicLoaderHexagonDYLD::GetThreadLocalData (const lldb::ModuleSP module, const lldb::ThreadSP thread)
+{
+ auto it = m_loaded_modules.find (module);
+ if (it == m_loaded_modules.end())
+ return LLDB_INVALID_ADDRESS;
+
+ addr_t link_map = it->second;
+ if (link_map == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ const HexagonDYLDRendezvous::ThreadInfo &metadata = m_rendezvous.GetThreadInfo();
+ if (!metadata.valid)
+ return LLDB_INVALID_ADDRESS;
+
+ // Get the thread pointer.
+ addr_t tp = thread->GetThreadPointer ();
+ if (tp == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ // Find the module's modid.
+ int modid = ReadInt (m_process, link_map + metadata.modid_offset);
+ if (modid == -1)
+ return LLDB_INVALID_ADDRESS;
+
+ // Lookup the DTV stucture for this thread.
+ addr_t dtv_ptr = tp + metadata.dtv_offset;
+ addr_t dtv = ReadPointer (dtv_ptr);
+ if (dtv == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ // Find the TLS block for this module.
+ addr_t dtv_slot = dtv + metadata.dtv_slot_size*modid;
+ addr_t tls_block = ReadPointer (dtv_slot + metadata.tls_offset);
+
+ Module *mod = module.get();
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ if (log)
+ log->Printf("DynamicLoaderHexagonDYLD::Performed TLS lookup: "
+ "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 ", modid=%i, tls_block=0x%" PRIx64,
+ mod->GetObjectName().AsCString(""), link_map, tp, modid, tls_block);
+
+ return tls_block;
+}
diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h
new file mode 100644
index 000000000000..aafa385c0fca
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h
@@ -0,0 +1,182 @@
+//===-- DynamicLoaderHexagon.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_DynamicLoaderHexagon_H_
+#define liblldb_DynamicLoaderHexagon_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "HexagonDYLDRendezvous.h"
+
+class DynamicLoaderHexagonDYLD : public lldb_private::DynamicLoader
+{
+public:
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance(lldb_private::Process *process, bool force);
+
+ DynamicLoaderHexagonDYLD(lldb_private::Process *process);
+
+ virtual
+ ~DynamicLoaderHexagonDYLD();
+
+ //------------------------------------------------------------------
+ // DynamicLoader protocol
+ //------------------------------------------------------------------
+
+ virtual void
+ DidAttach();
+
+ virtual void
+ DidLaunch();
+
+ virtual lldb::ThreadPlanSP
+ GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
+ bool stop_others);
+
+ virtual lldb_private::Error
+ CanLoadImage();
+
+ virtual lldb::addr_t
+ GetThreadLocalData (const lldb::ModuleSP module, const lldb::ThreadSP thread);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp(const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand(lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging(lldb_private::Stream *strm, lldb_private::Args &command);
+
+protected:
+ /// Runtime linker rendezvous structure.
+ HexagonDYLDRendezvous m_rendezvous;
+
+ /// Virtual load address of the inferior process.
+ lldb::addr_t m_load_offset;
+
+ /// Virtual entry address of the inferior process.
+ lldb::addr_t m_entry_point;
+
+ /// Rendezvous breakpoint.
+ lldb::break_id_t m_dyld_bid;
+
+ /// Loaded module list. (link map for each module)
+ std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>> m_loaded_modules;
+
+ /// Enables a breakpoint on a function called by the runtime
+ /// linker each time a module is loaded or unloaded.
+ bool
+ SetRendezvousBreakpoint();
+
+ /// Callback routine which updates the current list of loaded modules based
+ /// on the information supplied by the runtime linker.
+ static bool
+ RendezvousBreakpointHit(void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set
+ /// of loaded modules.
+ void
+ RefreshModules();
+
+ /// Updates the load address of every allocatable section in @p module.
+ ///
+ /// @param module The module to traverse.
+ ///
+ /// @param link_map_addr The virtual address of the link map for the @p module.
+ ///
+ /// @param base_addr The virtual base address @p module is loaded at.
+ void
+ UpdateLoadedSections(lldb::ModuleSP module,
+ lldb::addr_t link_map_addr,
+ lldb::addr_t base_addr);
+
+ /// Removes the loaded sections from the target in @p module.
+ ///
+ /// @param module The module to traverse.
+ void
+ UnloadSections(const lldb::ModuleSP module);
+
+ /// Locates or creates a module given by @p file and updates/loads the
+ /// resulting module at the virtual base address @p base_addr.
+ lldb::ModuleSP
+ LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t link_map_addr, lldb::addr_t base_addr);
+
+ /// Callback routine invoked when we hit the breakpoint on process entry.
+ ///
+ /// This routine is responsible for resolving the load addresses of all
+ /// dependent modules required by the inferior and setting up the rendezvous
+ /// breakpoint.
+ static bool
+ EntryBreakpointHit(void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ /// Helper for the entry breakpoint callback. Resolves the load addresses
+ /// of all dependent modules.
+ void
+ LoadAllCurrentModules();
+
+ /// Computes a value for m_load_offset returning the computed address on
+ /// success and LLDB_INVALID_ADDRESS on failure.
+ lldb::addr_t
+ ComputeLoadOffset();
+
+ /// Computes a value for m_entry_point returning the computed address on
+ /// success and LLDB_INVALID_ADDRESS on failure.
+ lldb::addr_t
+ GetEntryPoint();
+
+ /// Checks to see if the target module has changed, updates the target
+ /// accordingly and returns the target executable module.
+ lldb::ModuleSP
+ GetTargetExecutable();
+
+ /// return the address of the Rendezvous breakpoint
+ lldb::addr_t
+ FindRendezvousBreakpointAddress( );
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(DynamicLoaderHexagonDYLD);
+
+ const lldb_private::SectionList *
+ GetSectionListFromModule(const lldb::ModuleSP module) const;
+};
+
+#endif // liblldb_DynamicLoaderHexagonDYLD_H_
diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp
new file mode 100644
index 000000000000..5035e9d8bb17
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp
@@ -0,0 +1,403 @@
+//===-- HexagonDYLDRendezvous.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "HexagonDYLDRendezvous.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+/// Locates the address of the rendezvous structure. Returns the address on
+/// success and LLDB_INVALID_ADDRESS on failure.
+static addr_t
+ResolveRendezvousAddress(Process *process)
+{
+ addr_t info_location;
+ addr_t info_addr;
+ Error error;
+
+ info_location = process->GetImageInfoAddress();
+
+ if (info_location == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ info_addr = process->ReadPointerFromMemory(info_location, error);
+ if (error.Fail())
+ return LLDB_INVALID_ADDRESS;
+
+ if (info_addr == 0)
+ return LLDB_INVALID_ADDRESS;
+
+ return info_addr;
+}
+
+HexagonDYLDRendezvous::HexagonDYLDRendezvous(Process *process)
+ : m_process(process),
+ m_rendezvous_addr(LLDB_INVALID_ADDRESS),
+ m_current(),
+ m_previous(),
+ m_soentries(),
+ m_added_soentries(),
+ m_removed_soentries()
+{
+ m_thread_info.valid = false;
+
+ // Cache a copy of the executable path
+ if (m_process)
+ {
+ Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
+ if (exe_mod)
+ exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);
+ }
+}
+
+bool
+HexagonDYLDRendezvous::Resolve()
+{
+ const size_t word_size = 4;
+ Rendezvous info;
+ size_t address_size;
+ size_t padding;
+ addr_t info_addr;
+ addr_t cursor;
+
+ address_size = m_process->GetAddressByteSize();
+ padding = address_size - word_size;
+
+ if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
+ cursor = info_addr = ResolveRendezvousAddress(m_process);
+ else
+ cursor = info_addr = m_rendezvous_addr;
+
+ if (cursor == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (!(cursor = ReadWord(cursor, &info.version, word_size)))
+ return false;
+
+ if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))
+ return false;
+
+ if (!(cursor = ReadPointer(cursor, &info.brk)))
+ return false;
+
+ if (!(cursor = ReadWord(cursor, &info.state, word_size)))
+ return false;
+
+ if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))
+ return false;
+
+ // The rendezvous was successfully read. Update our internal state.
+ m_rendezvous_addr = info_addr;
+ m_previous = m_current;
+ m_current = info;
+
+ return UpdateSOEntries();
+}
+
+void
+HexagonDYLDRendezvous::SetRendezvousAddress( lldb::addr_t addr )
+{
+ m_rendezvous_addr = addr;
+}
+
+bool
+HexagonDYLDRendezvous::IsValid()
+{
+ return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
+}
+
+bool
+HexagonDYLDRendezvous::UpdateSOEntries()
+{
+ SOEntry entry;
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ // When the previous and current states are consistent this is the first
+ // time we have been asked to update. Just take a snapshot of the currently
+ // loaded modules.
+ if (m_previous.state == eConsistent && m_current.state == eConsistent)
+ return TakeSnapshot(m_soentries);
+
+ // If we are about to add or remove a shared object clear out the current
+ // state and take a snapshot of the currently loaded images.
+ if (m_current.state == eAdd || m_current.state == eDelete)
+ {
+ // this is a fudge so that we can clear the assert below.
+ m_previous.state = eConsistent;
+ // We hit this assert on the 2nd run of this function after running the calc example
+ assert(m_previous.state == eConsistent);
+ m_soentries.clear();
+ m_added_soentries.clear();
+ m_removed_soentries.clear();
+ return TakeSnapshot(m_soentries);
+ }
+ assert(m_current.state == eConsistent);
+
+ // Otherwise check the previous state to determine what to expect and update
+ // accordingly.
+ if (m_previous.state == eAdd)
+ return UpdateSOEntriesForAddition();
+ else if (m_previous.state == eDelete)
+ return UpdateSOEntriesForDeletion();
+
+ return false;
+}
+
+bool
+HexagonDYLDRendezvous::UpdateSOEntriesForAddition()
+{
+ SOEntry entry;
+ iterator pos;
+
+ assert(m_previous.state == eAdd);
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
+ {
+ if (!ReadSOEntryFromMemory(cursor, entry))
+ return false;
+
+ // Only add shared libraries and not the executable.
+ // On Linux this is indicated by an empty path in the entry.
+ // On FreeBSD it is the name of the executable.
+ if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
+ continue;
+
+ pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
+ if (pos == m_soentries.end())
+ {
+ m_soentries.push_back(entry);
+ m_added_soentries.push_back(entry);
+ }
+ }
+
+ return true;
+}
+
+bool
+HexagonDYLDRendezvous::UpdateSOEntriesForDeletion()
+{
+ SOEntryList entry_list;
+ iterator pos;
+
+ assert(m_previous.state == eDelete);
+
+ if (!TakeSnapshot(entry_list))
+ return false;
+
+ for (iterator I = begin(); I != end(); ++I)
+ {
+ pos = std::find(entry_list.begin(), entry_list.end(), *I);
+ if (pos == entry_list.end())
+ m_removed_soentries.push_back(*I);
+ }
+
+ m_soentries = entry_list;
+ return true;
+}
+
+bool
+HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list)
+{
+ SOEntry entry;
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
+ {
+ if (!ReadSOEntryFromMemory(cursor, entry))
+ return false;
+
+ // Only add shared libraries and not the executable.
+ // On Linux this is indicated by an empty path in the entry.
+ // On FreeBSD it is the name of the executable.
+ if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
+ continue;
+
+ entry_list.push_back(entry);
+ }
+
+ return true;
+}
+
+addr_t
+HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size)
+{
+ Error error;
+
+ *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
+ if (error.Fail())
+ return 0;
+
+ return addr + size;
+}
+
+addr_t
+HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst)
+{
+ Error error;
+
+ *dst = m_process->ReadPointerFromMemory(addr, error);
+ if (error.Fail())
+ return 0;
+
+ return addr + m_process->GetAddressByteSize();
+}
+
+std::string
+HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr)
+{
+ std::string str;
+ Error error;
+ size_t size;
+ char c;
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ return std::string();
+
+ for (;;) {
+ size = m_process->DoReadMemory(addr, &c, 1, error);
+ if (size != 1 || error.Fail())
+ return std::string();
+ if (c == 0)
+ break;
+ else {
+ str.push_back(c);
+ addr++;
+ }
+ }
+
+ return str;
+}
+
+bool
+HexagonDYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry)
+{
+ entry.clear();
+ entry.link_addr = addr;
+
+ if (!(addr = ReadPointer(addr, &entry.base_addr)))
+ return false;
+
+ if (!(addr = ReadPointer(addr, &entry.path_addr)))
+ return false;
+
+ if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
+ return false;
+
+ if (!(addr = ReadPointer(addr, &entry.next)))
+ return false;
+
+ if (!(addr = ReadPointer(addr, &entry.prev)))
+ return false;
+
+ entry.path = ReadStringFromMemory(entry.path_addr);
+
+ return true;
+}
+
+bool
+HexagonDYLDRendezvous::FindMetadata(const char *name, PThreadField field, uint32_t& value)
+{
+ Target& target = m_process->GetTarget();
+
+ SymbolContextList list;
+ if (!target.GetImages().FindSymbolsWithNameAndType (ConstString(name), eSymbolTypeAny, list))
+ return false;
+
+ Address address = list[0].symbol->GetAddress();
+ addr_t addr = address.GetLoadAddress (&target);
+ if (addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ Error error;
+ value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(addr + field*sizeof(uint32_t), sizeof(uint32_t), 0, error);
+ if (error.Fail())
+ return false;
+
+ if (field == eSize)
+ value /= 8; // convert bits to bytes
+
+ return true;
+}
+
+const HexagonDYLDRendezvous::ThreadInfo&
+HexagonDYLDRendezvous::GetThreadInfo()
+{
+ if (!m_thread_info.valid)
+ {
+ bool ok = true;
+
+ ok &= FindMetadata ("_thread_db_pthread_dtvp", eOffset, m_thread_info.dtv_offset);
+ ok &= FindMetadata ("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
+ ok &= FindMetadata ("_thread_db_link_map_l_tls_modid", eOffset, m_thread_info.modid_offset);
+ ok &= FindMetadata ("_thread_db_dtv_t_pointer_val", eOffset, m_thread_info.tls_offset);
+
+ if (ok)
+ m_thread_info.valid = true;
+ }
+
+ return m_thread_info;
+}
+
+void
+HexagonDYLDRendezvous::DumpToLog(Log *log) const
+{
+ int state = GetState();
+
+ if (!log)
+ return;
+
+ log->PutCString("HexagonDYLDRendezvous:");
+ log->Printf(" Address: %" PRIx64, GetRendezvousAddress());
+ log->Printf(" Version: %" PRIu64, GetVersion());
+ log->Printf(" Link : %" PRIx64, GetLinkMapAddress());
+ log->Printf(" Break : %" PRIx64, GetBreakAddress());
+ log->Printf(" LDBase : %" PRIx64, GetLDBase());
+ log->Printf(" State : %s",
+ (state == eConsistent) ? "consistent" :
+ (state == eAdd) ? "add" :
+ (state == eDelete) ? "delete" : "unknown");
+
+ iterator I = begin();
+ iterator E = end();
+
+ if (I != E)
+ log->PutCString("HexagonDYLDRendezvous SOEntries:");
+
+ for (int i = 1; I != E; ++I, ++i)
+ {
+ log->Printf("\n SOEntry [%d] %s", i, I->path.c_str());
+ log->Printf(" Base : %" PRIx64, I->base_addr);
+ log->Printf(" Path : %" PRIx64, I->path_addr);
+ log->Printf(" Dyn : %" PRIx64, I->dyn_addr);
+ log->Printf(" Next : %" PRIx64, I->next);
+ log->Printf(" Prev : %" PRIx64, I->prev);
+ }
+}
diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h
new file mode 100644
index 000000000000..cd5121330457
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h
@@ -0,0 +1,279 @@
+//===-- HexagonDYLDRendezvous.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_HexagonDYLDRendezvous_H_
+#define liblldb_HexagonDYLDRendezvous_H_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <string>
+
+// Other libraries and framework includes
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+namespace lldb_private
+{
+ class Process;
+}
+
+/// @class HexagonDYLDRendezvous
+/// @brief Interface to the runtime linker.
+///
+/// A structure is present in a processes memory space which is updated by the
+/// runtime liker each time a module is loaded or unloaded. This class provides
+/// an interface to this structure and maintains a consistent snapshot of the
+/// currently loaded modules.
+class HexagonDYLDRendezvous
+{
+
+ // This structure is used to hold the contents of the debug rendezvous
+ // information (struct r_debug) as found in the inferiors memory. Note that
+ // the layout of this struct is not binary compatible, it is simply large
+ // enough to hold the information on both 32 and 64 bit platforms.
+ struct Rendezvous {
+ uint64_t version;
+ lldb::addr_t map_addr;
+ lldb::addr_t brk;
+ uint64_t state;
+ lldb::addr_t ldbase;
+
+ Rendezvous()
+ : version (0)
+ , map_addr(LLDB_INVALID_ADDRESS)
+ , brk (LLDB_INVALID_ADDRESS)
+ , state (0)
+ , ldbase (0)
+ { }
+
+ };
+
+public:
+ // Various metadata supplied by the inferior's threading library to describe
+ // the per-thread state.
+ struct ThreadInfo {
+ bool valid; // whether we read valid metadata
+ uint32_t dtv_offset; // offset of DTV pointer within pthread
+ uint32_t dtv_slot_size; // size of one DTV slot
+ uint32_t modid_offset; // offset of module ID within link_map
+ uint32_t tls_offset; // offset of TLS pointer within DTV slot
+ };
+
+ HexagonDYLDRendezvous(lldb_private::Process *process);
+
+ /// Update the internal snapshot of runtime linker rendezvous and recompute
+ /// the currently loaded modules.
+ ///
+ /// This method should be called once one start up, then once each time the
+ /// runtime linker enters the function given by GetBreakAddress().
+ ///
+ /// @returns true on success and false on failure.
+ ///
+ /// @see GetBreakAddress().
+ bool
+ Resolve();
+
+ /// @returns true if this rendezvous has been located in the inferiors
+ /// address space and false otherwise.
+ bool
+ IsValid();
+
+ /// @returns the address of the rendezvous structure in the inferiors
+ /// address space.
+ lldb::addr_t
+ GetRendezvousAddress() const { return m_rendezvous_addr; }
+
+ /// Provide the dyld structure address
+ void
+ SetRendezvousAddress( lldb::addr_t );
+
+ /// @returns the version of the rendezvous protocol being used.
+ uint64_t
+ GetVersion() const { return m_current.version; }
+
+ /// @returns address in the inferiors address space containing the linked
+ /// list of shared object descriptors.
+ lldb::addr_t
+ GetLinkMapAddress() const { return m_current.map_addr; }
+
+ /// A breakpoint should be set at this address and Resolve called on each
+ /// hit.
+ ///
+ /// @returns the address of a function called by the runtime linker each
+ /// time a module is loaded/unloaded, or about to be loaded/unloaded.
+ ///
+ /// @see Resolve()
+ lldb::addr_t
+ GetBreakAddress() const { return m_current.brk; }
+
+ /// In hexagon it is possible that we can know the dyld breakpoint without
+ /// having to find it from the rendezvous structure
+ ///
+ void
+ SetBreakAddress( lldb::addr_t addr ) { m_current.brk = addr; }
+
+ /// Returns the current state of the rendezvous structure.
+ uint64_t
+ GetState() const { return m_current.state; }
+
+ /// @returns the base address of the runtime linker in the inferiors address
+ /// space.
+ lldb::addr_t
+ GetLDBase() const { return m_current.ldbase; }
+
+ /// @returns the thread layout metadata from the inferiors thread library.
+ const ThreadInfo&
+ GetThreadInfo();
+
+ /// @returns true if modules have been loaded into the inferior since the
+ /// last call to Resolve().
+ bool
+ ModulesDidLoad() const { return !m_added_soentries.empty(); }
+
+ /// @returns true if modules have been unloaded from the inferior since the
+ /// last call to Resolve().
+ bool
+ ModulesDidUnload() const { return !m_removed_soentries.empty(); }
+
+ void
+ DumpToLog(lldb_private::Log *log) const;
+
+ /// @brief Constants describing the state of the rendezvous.
+ ///
+ /// @see GetState().
+ enum RendezvousState
+ {
+ eConsistent = 0,
+ eAdd ,
+ eDelete ,
+ };
+
+ /// @brief Structure representing the shared objects currently loaded into
+ /// the inferior process.
+ ///
+ /// This object is a rough analogue to the struct link_map object which
+ /// actually lives in the inferiors memory.
+ struct SOEntry {
+ lldb::addr_t link_addr; ///< Address of this link_map.
+ lldb::addr_t base_addr; ///< Base address of the loaded object.
+ lldb::addr_t path_addr; ///< String naming the shared object.
+ lldb::addr_t dyn_addr; ///< Dynamic section of shared object.
+ lldb::addr_t next; ///< Address of next so_entry.
+ lldb::addr_t prev; ///< Address of previous so_entry.
+ std::string path; ///< File name of shared object.
+
+ SOEntry() { clear(); }
+
+ bool operator ==(const SOEntry &entry) {
+ return this->path == entry.path;
+ }
+
+ void clear() {
+ link_addr = 0;
+ base_addr = 0;
+ path_addr = 0;
+ dyn_addr = 0;
+ next = 0;
+ prev = 0;
+ path.clear();
+ }
+ };
+
+protected:
+ typedef std::list<SOEntry> SOEntryList;
+
+public:
+ typedef SOEntryList::const_iterator iterator;
+
+ /// Iterators over all currently loaded modules.
+ iterator begin() const { return m_soentries.begin(); }
+ iterator end() const { return m_soentries.end(); }
+
+ /// Iterators over all modules loaded into the inferior since the last call
+ /// to Resolve().
+ iterator loaded_begin() const { return m_added_soentries.begin(); }
+ iterator loaded_end() const { return m_added_soentries.end(); }
+
+ /// Iterators over all modules unloaded from the inferior since the last
+ /// call to Resolve().
+ iterator unloaded_begin() const { return m_removed_soentries.begin(); }
+ iterator unloaded_end() const { return m_removed_soentries.end(); }
+
+protected:
+ lldb_private::Process *m_process;
+
+ // Cached copy of executable pathname
+ char m_exe_path[PATH_MAX];
+
+ /// Location of the r_debug structure in the inferiors address space.
+ lldb::addr_t m_rendezvous_addr;
+
+ /// Current and previous snapshots of the rendezvous structure.
+ Rendezvous m_current;
+ Rendezvous m_previous;
+
+ /// List of SOEntry objects corresponding to the current link map state.
+ SOEntryList m_soentries;
+
+ /// List of SOEntry's added to the link map since the last call to Resolve().
+ SOEntryList m_added_soentries;
+
+ /// List of SOEntry's removed from the link map since the last call to
+ /// Resolve().
+ SOEntryList m_removed_soentries;
+
+ /// Threading metadata read from the inferior.
+ ThreadInfo m_thread_info;
+
+ /// Reads an unsigned integer of @p size bytes from the inferior's address
+ /// space starting at @p addr.
+ ///
+ /// @returns addr + size if the read was successful and false otherwise.
+ lldb::addr_t
+ ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size);
+
+ /// Reads an address from the inferior's address space starting at @p addr.
+ ///
+ /// @returns addr + target address size if the read was successful and
+ /// 0 otherwise.
+ lldb::addr_t
+ ReadPointer(lldb::addr_t addr, lldb::addr_t *dst);
+
+ /// Reads a null-terminated C string from the memory location starting at @p
+ /// addr.
+ std::string
+ ReadStringFromMemory(lldb::addr_t addr);
+
+ /// Reads an SOEntry starting at @p addr.
+ bool
+ ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry);
+
+ /// Updates the current set of SOEntries, the set of added entries, and the
+ /// set of removed entries.
+ bool
+ UpdateSOEntries();
+
+ bool
+ UpdateSOEntriesForAddition();
+
+ bool
+ UpdateSOEntriesForDeletion();
+
+ /// Reads the current list of shared objects according to the link map
+ /// supplied by the runtime linker.
+ bool
+ TakeSnapshot(SOEntryList &entry_list);
+
+ enum PThreadField { eSize, eNElem, eOffset };
+
+ bool FindMetadata(const char *name, PThreadField field, uint32_t& value);
+};
+
+#endif // liblldb_HexagonDYLDRendezvous_H_
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
index c079d0fc381f..04a6792fbf01 100644
--- a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
@@ -57,11 +57,10 @@ ParseAuxvEntry(DataExtractor &data,
DataBufferSP
AuxVector::GetAuxvData()
{
-#if defined(__linux__) || defined(__FreeBSD__)
- if (m_process->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
- return static_cast<ProcessElfCore *>(m_process)->GetAuxvData();
-#endif
- return lldb_private::Host::GetAuxvData(m_process);
+ if (m_process)
+ return m_process->GetAuxvData ();
+ else
+ return DataBufferSP ();
}
void
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
index 3c5dcc5222af..0e203fe43a79 100644
--- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
@@ -14,6 +14,7 @@
#include "lldb/Core/Error.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
@@ -28,21 +29,61 @@ using namespace lldb_private;
static addr_t
ResolveRendezvousAddress(Process *process)
{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
addr_t info_location;
addr_t info_addr;
Error error;
+ // Try to get it from our process. This might be a remote process and might
+ // grab it via some remote-specific mechanism.
info_location = process->GetImageInfoAddress();
+ if (log)
+ log->Printf ("%s info_location = 0x%" PRIx64, __FUNCTION__, info_location);
+ // If the process fails to return an address, fall back to seeing if the local object file can help us find it.
if (info_location == LLDB_INVALID_ADDRESS)
+ {
+ Target *target = process ? &process->GetTarget() : nullptr;
+ if (target)
+ {
+ ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress(target);
+
+ if (addr.IsValid())
+ {
+ info_location = addr.GetLoadAddress(target);
+ if (log)
+ log->Printf ("%s resolved via direct object file approach to 0x%" PRIx64, __FUNCTION__, info_location);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("%s FAILED - direct object file approach did not yield a valid address", __FUNCTION__);
+ }
+ }
+ }
+
+ if (info_location == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf ("%s FAILED - invalid info address", __FUNCTION__);
return LLDB_INVALID_ADDRESS;
+ }
info_addr = process->ReadPointerFromMemory(info_location, error);
if (error.Fail())
+ {
+ if (log)
+ log->Printf ("%s FAILED - could not read from the info location: %s", __FUNCTION__, error.AsCString ());
return LLDB_INVALID_ADDRESS;
+ }
if (info_addr == 0)
+ {
+ if (log)
+ log->Printf ("%s FAILED - the rendezvous address contained at 0x%" PRIx64 " returned a null value", __FUNCTION__, info_location);
return LLDB_INVALID_ADDRESS;
+ }
return info_addr;
}
@@ -56,6 +97,8 @@ DYLDRendezvous::DYLDRendezvous(Process *process)
m_added_soentries(),
m_removed_soentries()
{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
m_thread_info.valid = false;
// Cache a copy of the executable path
@@ -63,13 +106,24 @@ DYLDRendezvous::DYLDRendezvous(Process *process)
{
Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
if (exe_mod)
+ {
exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);
+ if (log)
+ log->Printf ("DYLDRendezvous::%s exe module executable path set: '%s'", __FUNCTION__, m_exe_path);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("DYLDRendezvous::%s cannot cache exe module path: null executable module pointer", __FUNCTION__);
+ }
}
}
bool
DYLDRendezvous::Resolve()
{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
const size_t word_size = 4;
Rendezvous info;
size_t address_size;
@@ -79,12 +133,16 @@ DYLDRendezvous::Resolve()
address_size = m_process->GetAddressByteSize();
padding = address_size - word_size;
+ if (log)
+ log->Printf ("DYLDRendezvous::%s address size: %zu, padding %zu", __FUNCTION__, address_size, padding);
if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
cursor = info_addr = ResolveRendezvousAddress(m_process);
else
cursor = info_addr = m_rendezvous_addr;
-
+ if (log)
+ log->Printf ("DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__, cursor);
+
if (cursor == LLDB_INVALID_ADDRESS)
return false;
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index 286b1ef62d9a..549e5f9b5345 100644
--- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -468,7 +468,7 @@ DynamicLoaderPOSIXDYLD::GetThreadLocalData (const lldb::ModuleSP module, const l
if (modid == -1)
return LLDB_INVALID_ADDRESS;
- // Lookup the DTV stucture for this thread.
+ // Lookup the DTV structure for this thread.
addr_t dtv_ptr = tp + metadata.dtv_offset;
addr_t dtv = ReadPointer (dtv_ptr);
if (dtv == LLDB_INVALID_ADDRESS)
diff --git a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h
index a99435fa32ad..ea33164cf823 100644
--- a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h
+++ b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h
@@ -17,7 +17,6 @@
#include <string>
// Other libraries and framework includes
-#include "llvm/Support/MachO.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Host/FileSpec.h"
diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
index f1cb41d5a913..fa8681ed69fe 100644
--- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
+++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
@@ -24,6 +24,7 @@
#include "Plugins/Process/Utility/ARMUtils.h"
#include "Utility/ARM_DWARF_Registers.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/MathExtras.h" // for SignExtend32 template function
// and countTrailingZeros function
@@ -266,7 +267,7 @@ EmulateInstructionARM::WriteBits32Unknown (int n)
}
bool
-EmulateInstructionARM::GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo &reg_info)
+EmulateInstructionARM::GetRegisterInfo (lldb::RegisterKind reg_kind, uint32_t reg_num, RegisterInfo &reg_info)
{
if (reg_kind == eRegisterKindGeneric)
{
@@ -2169,7 +2170,7 @@ EmulateInstructionARM::EmulateVPOP (const uint32_t opcode, const ARMEncoding enc
addr_t sp_offset = imm32;
addr_t addr = sp;
uint32_t i;
- uint64_t data; // uint64_t to accomodate 64-bit registers.
+ uint64_t data; // uint64_t to accommodate 64-bit registers.
EmulateInstruction::Context context;
if (conditional)
@@ -3626,7 +3627,7 @@ EmulateInstructionARM::EmulateLDMDA (const uint32_t opcode, const ARMEncoding en
}
// LDMDB loads multiple registers from consecutive memory locations using an address from a base register. The
-// consecutive memory lcoations end just below this address, and the address of the lowest of those locations can
+// consecutive memory locations end just below this address, and the address of the lowest of those locations can
// be optionally written back to the base register.
bool
EmulateInstructionARM::EmulateLDMDB (const uint32_t opcode, const ARMEncoding encoding)
@@ -4033,7 +4034,7 @@ EmulateInstructionARM::EmulateLDRRtRnImm (const uint32_t opcode, const ARMEncodi
}
// STM (Store Multiple Increment After) stores multiple registers to consecutive memory locations using an address
-// from a base register. The consecutive memory locations start at this address, and teh address just above the last
+// from a base register. The consecutive memory locations start at this address, and the address just above the last
// of those locations can optionally be written back to the base register.
bool
EmulateInstructionARM::EmulateSTM (const uint32_t opcode, const ARMEncoding encoding)
@@ -4588,7 +4589,7 @@ EmulateInstructionARM::EmulateSTMIB (const uint32_t opcode, const ARMEncoding en
return true;
}
-// STR (store immediate) calcualtes an address from a base register value and an immediate offset, and stores a word
+// STR (store immediate) calculates an address from a base register value and an immediate offset, and stores a word
// from a register to memory. It can use offset, post-indexed, or pre-indexed addressing.
bool
EmulateInstructionARM::EmulateSTRThumb (const uint32_t opcode, const ARMEncoding encoding)
@@ -5076,7 +5077,7 @@ EmulateInstructionARM::EmulateSTRBThumb (const uint32_t opcode, const ARMEncodin
}
// STRH (register) calculates an address from a base register value and an offset register value, and stores a
-// halfword from a register to memory. The offset register alue can be shifted left by 0, 1, 2, or 3 bits.
+// halfword from a register to memory. The offset register value can be shifted left by 0, 1, 2, or 3 bits.
bool
EmulateInstructionARM::EmulateSTRHRegister (const uint32_t opcode, const ARMEncoding encoding)
{
@@ -5941,7 +5942,7 @@ EmulateInstructionARM::EmulateLDRImmediateARM (const uint32_t opcode, const ARME
}
// LDR (register) calculates an address from a base register value and an offset register value, loads a word
-// from memory, and writes it to a resgister. The offset register value can optionally be shifted.
+// from memory, and writes it to a register. The offset register value can optionally be shifted.
bool
EmulateInstructionARM::EmulateLDRRegister (const uint32_t opcode, const ARMEncoding encoding)
{
@@ -11033,7 +11034,7 @@ EmulateInstructionARM::EmulateVSTM (const uint32_t opcode, const ARMEncoding enc
}
// A8.6.320
-// This instruciton loads a single extension register fronm memory, using an address from an ARM core register, with
+// This instruction loads a single extension register from memory, using an address from an ARM core register, with
// an optional offset.
bool
EmulateInstructionARM::EmulateVLDR (const uint32_t opcode, ARMEncoding encoding)
@@ -11638,7 +11639,7 @@ EmulateInstructionARM::EmulateVLD1Single (const uint32_t opcode, const ARMEncodi
}
// A8.6.391 VST1 (multiple single elements)
-// Vector Store (multiple single elements) stores elements to memory from one, two, three, or four regsiters, without
+// Vector Store (multiple single elements) stores elements to memory from one, two, three, or four registers, without
// interleaving. Every element of each register is stored.
bool
EmulateInstructionARM::EmulateVST1Multiple (const uint32_t opcode, ARMEncoding encoding)
@@ -12506,7 +12507,7 @@ EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode, uint32
{ 0xfe500000, 0xf8100000, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRFE, "rfe{<amode>} <Rn>{!}" }
};
- static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);
+ static const size_t k_num_arm_opcodes = llvm::array_lengthof(g_arm_opcodes);
for (size_t i=0; i<k_num_arm_opcodes; ++i)
{
@@ -12832,7 +12833,7 @@ EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode, uint
{ 0xfffff080, 0xfa1ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTH, "uxth<c>.w <Rd>,<Rm>{,<rotation>}" },
};
- const size_t k_num_thumb_opcodes = sizeof(g_thumb_opcodes)/sizeof(ARMOpcode);
+ const size_t k_num_thumb_opcodes = llvm::array_lengthof(g_thumb_opcodes);
for (size_t i=0; i<k_num_thumb_opcodes; ++i)
{
if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value &&
@@ -13019,7 +13020,7 @@ EmulateInstructionARM::ConditionPassed (const uint32_t opcode, bool *is_conditio
break;
case 7:
// Always execute (cond == 0b1110, or the special 0b1111 which gives
- // opcodes different meanings, but always means execution happpens.
+ // opcodes different meanings, but always means execution happens.
if (is_conditional)
*is_conditional = false;
result = true;
@@ -13307,7 +13308,8 @@ EmulateInstructionARM::AddWithCarry (uint32_t x, uint32_t y, uint8_t carry_in)
uint32_t
EmulateInstructionARM::ReadCoreReg(uint32_t num, bool *success)
{
- uint32_t reg_kind, reg_num;
+ lldb::RegisterKind reg_kind;
+ uint32_t reg_num;
switch (num)
{
case SP_REG:
@@ -13388,7 +13390,8 @@ EmulateInstructionARM::WriteCoreRegOptionalFlags (Context &context,
}
else
{
- uint32_t reg_kind, reg_num;
+ lldb::RegisterKind reg_kind;
+ uint32_t reg_num;
switch (Rd)
{
case SP_REG:
diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
index 81e78847a1f3..d107ca6bc702 100644
--- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
+++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
@@ -170,7 +170,7 @@ public:
TestEmulation (Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data);
virtual bool
- GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo &reg_info);
+ GetRegisterInfo (lldb::RegisterKind reg_kind, uint32_t reg_num, RegisterInfo &reg_info);
virtual bool
diff --git a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
new file mode 100644
index 000000000000..3900af9b00d0
--- /dev/null
+++ b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
@@ -0,0 +1,719 @@
+//===-- EmulateInstructionARM64.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EmulateInstructionARM64.h"
+
+#include <stdlib.h>
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/UnwindPlan.h"
+
+#include "Plugins/Process/Utility/ARMDefines.h"
+#include "Plugins/Process/Utility/ARMUtils.h"
+#include "Utility/ARM64_DWARF_Registers.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/MathExtras.h" // for SignExtend32 template function
+ // and CountTrailingZeros_32 function
+
+#include "Plugins/Process/Utility/InstructionUtils.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define No_VFP 0
+#define VFPv1 (1u << 1)
+#define VFPv2 (1u << 2)
+#define VFPv3 (1u << 3)
+#define AdvancedSIMD (1u << 4)
+
+#define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD)
+#define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD)
+#define VFPv2v3 (VFPv2 | VFPv3)
+
+#define UInt(x) ((uint64_t)x)
+#define SInt(x) ((int64_t)x)
+#define bit bool
+#define boolean bool
+#define integer int64_t
+
+static inline bool
+IsZero(uint64_t x)
+{
+ return x == 0;
+}
+
+static inline uint64_t
+NOT(uint64_t x)
+{
+ return ~x;
+}
+
+#if 0
+// LSL_C()
+// =======
+static inline uint64_t
+LSL_C (uint64_t x, integer shift, bool &carry_out)
+{
+ assert (shift >= 0);
+ uint64_t result = x << shift;
+ carry_out = ((1ull << (64-1)) >> (shift - 1)) != 0;
+ return result;
+}
+#endif
+
+// LSL()
+// =====
+
+static inline uint64_t
+LSL(uint64_t x, integer shift)
+{
+ if (shift == 0)
+ return x;
+ return x << shift;
+}
+
+// AddWithCarry()
+// ===============
+static inline uint64_t
+AddWithCarry (uint32_t N, uint64_t x, uint64_t y, bit carry_in, EmulateInstructionARM64::ProcState &proc_state)
+{
+ uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in);
+ int64_t signed_sum = SInt(x) + SInt(y) + UInt(carry_in);
+ uint64_t result = unsigned_sum;
+ if (N < 64)
+ result = Bits64 (result, N-1, 0);
+ proc_state.N = Bit64(result, N-1);
+ proc_state.Z = IsZero(result);
+ proc_state.C = UInt(result) == unsigned_sum;
+ proc_state.V = SInt(result) == signed_sum;
+ return result;
+}
+
+// ConstrainUnpredictable()
+// ========================
+
+EmulateInstructionARM64::ConstraintType
+ConstrainUnpredictable (EmulateInstructionARM64::Unpredictable which)
+{
+ EmulateInstructionARM64::ConstraintType result = EmulateInstructionARM64::Constraint_UNKNOWN;
+ switch (which)
+ {
+ case EmulateInstructionARM64::Unpredictable_WBOVERLAP:
+ case EmulateInstructionARM64::Unpredictable_LDPOVERLAP:
+ // TODO: don't know what to really do here? Pseudo code says:
+ // set result to one of above Constraint behaviours or UNDEFINED
+ break;
+ }
+ return result;
+}
+
+
+
+//----------------------------------------------------------------------
+//
+// EmulateInstructionARM implementation
+//
+//----------------------------------------------------------------------
+
+void
+EmulateInstructionARM64::Initialize ()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic (),
+ GetPluginDescriptionStatic (),
+ CreateInstance);
+}
+
+void
+EmulateInstructionARM64::Terminate ()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+ConstString
+EmulateInstructionARM64::GetPluginNameStatic ()
+{
+ ConstString g_plugin_name ("lldb.emulate-instruction.arm64");
+ return g_plugin_name;
+}
+
+lldb_private::ConstString
+EmulateInstructionARM64::GetPluginName()
+{
+ static ConstString g_plugin_name ("EmulateInstructionARM64");
+ return g_plugin_name;
+}
+
+const char *
+EmulateInstructionARM64::GetPluginDescriptionStatic ()
+{
+ return "Emulate instructions for the ARM64 architecture.";
+}
+
+EmulateInstruction *
+EmulateInstructionARM64::CreateInstance (const ArchSpec &arch, InstructionType inst_type)
+{
+ if (EmulateInstructionARM64::SupportsEmulatingInstructionsOfTypeStatic(inst_type))
+ {
+ if (arch.GetTriple().getArch() == llvm::Triple::aarch64)
+ {
+ std::auto_ptr<EmulateInstructionARM64> emulate_insn_ap (new EmulateInstructionARM64 (arch));
+ if (emulate_insn_ap.get())
+ return emulate_insn_ap.release();
+ }
+ }
+
+ return NULL;
+}
+
+bool
+EmulateInstructionARM64::SetTargetTriple (const ArchSpec &arch)
+{
+ if (arch.GetTriple().getArch () == llvm::Triple::arm)
+ return true;
+ else if (arch.GetTriple().getArch () == llvm::Triple::thumb)
+ return true;
+
+ return false;
+}
+
+bool
+EmulateInstructionARM64::GetRegisterInfo (RegisterKind reg_kind, uint32_t reg_num, RegisterInfo &reg_info)
+{
+ if (reg_kind == eRegisterKindGeneric)
+ {
+ switch (reg_num)
+ {
+ case LLDB_REGNUM_GENERIC_PC: reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::pc; break;
+ case LLDB_REGNUM_GENERIC_SP: reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::sp; break;
+ case LLDB_REGNUM_GENERIC_FP: reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::fp; break;
+ case LLDB_REGNUM_GENERIC_RA: reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::lr; break;
+ case LLDB_REGNUM_GENERIC_FLAGS:
+ // There is no DWARF register number for the CPSR right now...
+ reg_info.name = "cpsr";
+ reg_info.alt_name = NULL;
+ reg_info.byte_size = 4;
+ reg_info.byte_offset = 0;
+ reg_info.encoding = eEncodingUint;
+ reg_info.format = eFormatHex;
+ for (uint32_t i=0; i<lldb::kNumRegisterKinds; ++i)
+ reg_info.kinds[reg_kind] = LLDB_INVALID_REGNUM;
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+ return true;
+
+ default: return false;
+ }
+ }
+
+ if (reg_kind == eRegisterKindDWARF)
+ return arm64_dwarf::GetRegisterInfo(reg_num, reg_info);
+ return false;
+}
+
+EmulateInstructionARM64::Opcode*
+EmulateInstructionARM64::GetOpcodeForInstruction (const uint32_t opcode)
+{
+ static EmulateInstructionARM64::Opcode
+ g_opcodes[] =
+ {
+ //----------------------------------------------------------------------
+ // Prologue instructions
+ //----------------------------------------------------------------------
+
+ // push register(s)
+ { 0xff000000, 0xd1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUB <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}" },
+ { 0xff000000, 0xf1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUBS <Xd>, <Xn|SP>, #<imm> {, <shift>}" },
+ { 0xff000000, 0x91000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADD <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}" },
+ { 0xff000000, 0xb1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADDS <Xd>, <Xn|SP>, #<imm> {, <shift>}" },
+
+
+ { 0xff000000, 0x51000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUB <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}" },
+ { 0xff000000, 0x71000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUBS <Wd>, <Wn|WSP>, #<imm> {, <shift>}" },
+ { 0xff000000, 0x11000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADD <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}" },
+ { 0xff000000, 0x31000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADDS <Wd>, <Wn|WSP>, #<imm> {, <shift>}" },
+
+ { 0xffc00000, 0x29000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0xa9000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0x2d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <St>, <St2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0x6d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0xad000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]" },
+
+ { 0xffc00000, 0xad800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x2d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <St>, <St2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x29800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x6d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xa9800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!" },
+
+ };
+ static const size_t k_num_arm_opcodes = llvm::array_lengthof(g_opcodes);
+
+ for (size_t i=0; i<k_num_arm_opcodes; ++i)
+ {
+ if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value)
+ return &g_opcodes[i];
+ }
+ return NULL;
+}
+
+bool
+EmulateInstructionARM64::ReadInstruction ()
+{
+ bool success = false;
+ m_addr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success);
+ if (success)
+ {
+ Context read_inst_context;
+ read_inst_context.type = eContextReadOpcode;
+ read_inst_context.SetNoArgs ();
+ m_opcode.SetOpcode32 (ReadMemoryUnsigned (read_inst_context, m_addr, 4, 0, &success), GetByteOrder());
+ }
+ if (!success)
+ m_addr = LLDB_INVALID_ADDRESS;
+ return success;
+}
+
+
+bool
+EmulateInstructionARM64::EvaluateInstruction (uint32_t evaluate_options)
+{
+ const uint32_t opcode = m_opcode.GetOpcode32();
+ Opcode *opcode_data = GetOpcodeForInstruction(opcode);
+ if (opcode_data == NULL)
+ return false;
+
+ //printf ("opcode template for 0x%8.8x: %s\n", opcode, opcode_data->name);
+ const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
+ m_ignore_conditions = evaluate_options & eEmulateInstructionOptionIgnoreConditions;
+
+ bool success = false;
+// if (m_opcode_cpsr == 0 || m_ignore_conditions == false)
+// {
+// m_opcode_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, // use eRegisterKindDWARF is we ever get a cpsr DWARF register number
+// LLDB_REGNUM_GENERIC_FLAGS, // use arm64_dwarf::cpsr if we ever get one
+// 0,
+// &success);
+// }
+
+ // Only return false if we are unable to read the CPSR if we care about conditions
+ if (success == false && m_ignore_conditions == false)
+ return false;
+
+ uint32_t orig_pc_value = 0;
+ if (auto_advance_pc)
+ {
+ orig_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::pc, 0, &success);
+ if (!success)
+ return false;
+ }
+
+ // Call the Emulate... function.
+ success = (this->*opcode_data->callback) (opcode);
+ if (!success)
+ return false;
+
+ if (auto_advance_pc)
+ {
+ uint32_t new_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::pc, 0, &success);
+ if (!success)
+ return false;
+
+ if (auto_advance_pc && (new_pc_value == orig_pc_value))
+ {
+ EmulateInstruction::Context context;
+ context.type = eContextAdvancePC;
+ context.SetNoArgs();
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::pc, orig_pc_value + 4))
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM64::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ const bool can_replace = false;
+
+ // Our previous Call Frame Address is the stack pointer
+ row->SetCFARegister (arm64_dwarf::sp);
+
+ // Our previous PC is in the LR
+ row->SetRegisterLocationToRegister(arm64_dwarf::pc, arm64_dwarf::lr, can_replace);
+
+ unwind_plan.AppendRow (row);
+
+ // All other registers are the same.
+
+ unwind_plan.SetSourceName ("EmulateInstructionARM64");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
+ return true;
+}
+
+
+
+bool
+EmulateInstructionARM64::Emulate_addsub_imm (const uint32_t opcode)
+{
+ // integer d = UInt(Rd);
+ // integer n = UInt(Rn);
+ // integer datasize = if sf == 1 then 64 else 32;
+ // boolean sub_op = (op == 1);
+ // boolean setflags = (S == 1);
+ // bits(datasize) imm;
+ //
+ // case shift of
+ // when '00' imm = ZeroExtend(imm12, datasize);
+ // when '01' imm = ZeroExtend(imm12 : Zeros(12), datasize);
+ // when '1x' UNDEFINED;
+ //
+ //
+ // bits(datasize) result;
+ // bits(datasize) operand1 = if n == 31 then SP[] else X[n];
+ // bits(datasize) operand2 = imm;
+ // bits(4) nzcv;
+ // bit carry_in;
+ //
+ // if sub_op then
+ // operand2 = NOT(operand2);
+ // carry_in = 1;
+ // else
+ // carry_in = 0;
+ //
+ // (result, nzcv) = AddWithCarry(operand1, operand2, carry_in);
+ //
+ // if setflags then
+ // PSTATE.NZCV = nzcv;
+ //
+ // if d == 31 && !setflags then
+ // SP[] = result;
+ // else
+ // X[d] = result;
+
+ const uint32_t sf = Bit32(opcode, 31);
+ const uint32_t op = Bit32(opcode, 30);
+ const uint32_t S = Bit32(opcode, 29);
+ const uint32_t shift = Bits32(opcode, 23, 22);
+ const uint32_t imm12 = Bits32(opcode, 21, 10);
+ const uint32_t Rn = Bits32(opcode, 9, 5);
+ const uint32_t Rd = Bits32(opcode, 4, 0);
+
+ bool success = false;
+
+ const uint32_t d = UInt(Rd);
+ const uint32_t n = UInt(Rn);
+ const uint32_t datasize = (sf == 1) ? 64 : 32;
+ boolean sub_op = op == 1;
+ boolean setflags = S == 1;
+ uint64_t imm;
+
+ switch (shift)
+ {
+ case 0: imm = imm12; break;
+ case 1: imm = imm12 << 12; break;
+ default: return false; // UNDEFINED;
+ }
+ uint64_t result;
+ uint64_t operand1 = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::x0 + n, 0, &success);
+ uint64_t operand2 = imm;
+ bit carry_in;
+
+ if (sub_op)
+ {
+ operand2 = NOT(operand2);
+ carry_in = 1;
+ imm = -imm; // For the Register plug offset context below
+ }
+ else
+ {
+ carry_in = 0;
+ }
+
+ ProcState proc_state;
+
+ result = AddWithCarry (datasize, operand1, operand2, carry_in, proc_state);
+
+ if (setflags)
+ {
+ m_emulated_pstate.N = proc_state.N;
+ m_emulated_pstate.Z = proc_state.Z;
+ m_emulated_pstate.C = proc_state.C;
+ m_emulated_pstate.V = proc_state.V;
+ }
+
+ Context context;
+ RegisterInfo reg_info_Rn;
+ if (arm64_dwarf::GetRegisterInfo (n, reg_info_Rn))
+ context.SetRegisterPlusOffset (reg_info_Rn, imm);
+
+ if ((n == arm64_dwarf::sp || n == arm64_dwarf::fp) &&
+ d == arm64_dwarf::sp &&
+ !setflags)
+ {
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ }
+ else if (d == arm64_dwarf::fp &&
+ n == arm64_dwarf::sp &&
+ !setflags)
+ {
+ context.type = EmulateInstruction::eContextSetFramePointer;
+ }
+ else
+ {
+ context.type = EmulateInstruction::eContextImmediate;
+ }
+ WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::x0 + d, result);
+
+ return false;
+}
+
+bool
+EmulateInstructionARM64::Emulate_ldstpair_off (const uint32_t opcode)
+{
+ return Emulate_ldstpair (opcode, AddrMode_OFF);
+}
+
+
+bool
+EmulateInstructionARM64::Emulate_ldstpair_pre (const uint32_t opcode)
+{
+ return Emulate_ldstpair (opcode, AddrMode_PRE);
+}
+
+bool
+EmulateInstructionARM64::Emulate_ldstpair (const uint32_t opcode, AddrMode a_mode)
+{
+ uint32_t opc = Bits32(opcode, 31, 30);
+ uint32_t V = Bit32(opcode, 26);
+ uint32_t L = Bit32(opcode, 22);
+ uint32_t imm7 = Bits32(opcode, 21, 15);
+ uint32_t Rt2 = Bits32(opcode, 14, 10);
+ uint32_t Rn = Bits32(opcode, 9, 5);
+ uint32_t Rt = Bits32(opcode, 4, 0);
+
+ integer n = UInt(Rn);
+ integer t = UInt(Rt);
+ integer t2 = UInt(Rt2);
+ uint64_t idx;
+
+ MemOp memop = L == 1 ? MemOp_LOAD : MemOp_STORE;
+ boolean vector = (V == 1);
+ //AccType acctype = AccType_NORMAL;
+ boolean is_signed = false;
+ boolean wback = a_mode != AddrMode_OFF;
+ boolean wb_unknown = false;
+ boolean rt_unknown = false;
+ integer scale;
+ integer size;
+
+ if (opc == 3)
+ return false; // UNDEFINED
+
+ if (vector)
+ {
+ scale = 2 + UInt(opc);
+ }
+ else
+ {
+ scale = (opc & 2) ? 3 : 2;
+ is_signed = (opc & 1) != 0;
+ if (is_signed && memop == MemOp_STORE)
+ return false; // UNDEFINED
+ }
+
+ if (!vector && wback && ((t == n) || (t2 == n)))
+ {
+ switch (ConstrainUnpredictable(Unpredictable_WBOVERLAP))
+ {
+ case Constraint_UNKNOWN:
+ wb_unknown = true; // writeback is UNKNOWN
+ break;
+
+ case Constraint_SUPPRESSWB:
+ wback = false; // writeback is suppressed
+ break;
+
+ case Constraint_NOP:
+ memop = MemOp_NOP; // do nothing
+ wback = false;
+ break;
+
+ case Constraint_NONE:
+ break;
+ }
+ }
+
+ if (memop == MemOp_LOAD && t == t2)
+ {
+ switch (ConstrainUnpredictable(Unpredictable_LDPOVERLAP))
+ {
+ case Constraint_UNKNOWN:
+ rt_unknown = true; // result is UNKNOWN
+ break;
+
+ case Constraint_NOP:
+ memop = MemOp_NOP; // do nothing
+ wback = false;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ idx = LSL(llvm::SignExtend64<7>(imm7), scale);
+ size = (integer)1 << scale;
+ uint64_t datasize = size * 8;
+ uint64_t address;
+ uint64_t wb_address;
+
+ RegisterValue data_Rt;
+ RegisterValue data_Rt2;
+
+ // if (vector)
+ // CheckFPEnabled(false);
+
+ RegisterInfo reg_info_base;
+ RegisterInfo reg_info_Rt;
+ RegisterInfo reg_info_Rt2;
+ if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::x0 + n, reg_info_base))
+ return false;
+
+ if (vector)
+ {
+ if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::v0 + n, reg_info_Rt))
+ return false;
+ if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::v0 + n, reg_info_Rt2))
+ return false;
+ }
+ else
+ {
+ if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::x0 + t, reg_info_Rt))
+ return false;
+ if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::x0 + t2, reg_info_Rt2))
+ return false;
+ }
+
+ bool success = false;
+ if (n == 31)
+ {
+ //CheckSPAlignment();
+ address = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::sp, 0, &success);
+ }
+ else
+ address = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::x0 + n, 0, &success);
+
+ wb_address = address + idx;
+ if (a_mode != AddrMode_POST)
+ address = wb_address;
+
+ Context context_t;
+ Context context_t2;
+
+ if (n == 31 || n == 29) // if this store is based off of the sp or fp register
+ {
+ context_t.type = eContextPushRegisterOnStack;
+ context_t2.type = eContextPushRegisterOnStack;
+ }
+ else
+ {
+ context_t.type = eContextRegisterPlusOffset;
+ context_t2.type = eContextRegisterPlusOffset;
+ }
+ context_t.SetRegisterToRegisterPlusOffset (reg_info_Rt, reg_info_base, 0);
+ context_t2.SetRegisterToRegisterPlusOffset (reg_info_Rt2, reg_info_base, size);
+ uint8_t buffer [RegisterValue::kMaxRegisterByteSize];
+ Error error;
+
+ switch (memop)
+ {
+ case MemOp_STORE:
+ {
+ if (!ReadRegister (&reg_info_Rt, data_Rt))
+ return false;
+
+ if (data_Rt.GetAsMemoryData(&reg_info_Rt, buffer, reg_info_Rt.byte_size, eByteOrderLittle, error) == 0)
+ return false;
+
+ if (!WriteMemory(context_t, address + 0, buffer, reg_info_Rt.byte_size))
+ return false;
+
+ if (!ReadRegister (&reg_info_Rt2, data_Rt2))
+ return false;
+
+ if (data_Rt2.GetAsMemoryData(&reg_info_Rt2, buffer, reg_info_Rt2.byte_size, eByteOrderLittle, error) == 0)
+ return false;
+
+ if (!WriteMemory(context_t2, address + size, buffer, reg_info_Rt2.byte_size))
+ return false;
+ }
+ break;
+
+ case MemOp_LOAD:
+ {
+ if (rt_unknown)
+ memset (buffer, 'U', reg_info_Rt.byte_size);
+ else
+ {
+ if (!ReadMemory (context_t, address, buffer, reg_info_Rt.byte_size))
+ return false;
+ }
+
+ if (data_Rt.SetFromMemoryData(&reg_info_Rt, buffer, reg_info_Rt.byte_size, eByteOrderLittle, error) == 0)
+ return false;
+
+ if (!vector && is_signed && !data_Rt.SignExtend (datasize))
+ return false;
+
+ if (!WriteRegister (context_t, &reg_info_Rt, data_Rt))
+ return false;
+
+ if (!rt_unknown)
+ {
+ if (!ReadMemory (context_t2, address + size, buffer, reg_info_Rt2.byte_size))
+ return false;
+ }
+
+ if (data_Rt2.SetFromMemoryData(&reg_info_Rt2, buffer, reg_info_Rt2.byte_size, eByteOrderLittle, error) == 0)
+ return false;
+
+ if (!vector && is_signed && !data_Rt2.SignExtend (datasize))
+ return false;
+
+ if (!WriteRegister (context_t2, &reg_info_Rt2, data_Rt2))
+ return false;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (wback)
+ {
+ if (wb_unknown)
+ wb_address = LLDB_INVALID_ADDRESS;
+ Context context;
+ context.SetImmediateSigned (idx);
+ if (n == 31)
+ context.type = eContextAdjustStackPointer;
+ else
+ context.type = eContextAdjustBaseRegister;
+ WriteRegisterUnsigned (context, &reg_info_base, wb_address);
+ }
+ return true;
+}
diff --git a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h
new file mode 100644
index 000000000000..7e18d09a0ee2
--- /dev/null
+++ b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h
@@ -0,0 +1,297 @@
+//===-- EmulateInstructionARM64.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef EmulateInstructionARM64_h_
+#define EmulateInstructionARM64_h_
+
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Interpreter/OptionValue.h"
+#include "Plugins/Process/Utility/ARMDefines.h"
+
+class EmulateInstructionARM64 : public lldb_private::EmulateInstruction
+{
+public:
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic ();
+
+ static const char *
+ GetPluginDescriptionStatic ();
+
+ static lldb_private::EmulateInstruction *
+ CreateInstance (const lldb_private::ArchSpec &arch,
+ lldb_private::InstructionType inst_type);
+
+ static bool
+ SupportsEmulatingInstructionsOfTypeStatic (lldb_private::InstructionType inst_type)
+ {
+ switch (inst_type)
+ {
+ case lldb_private::eInstructionTypeAny:
+ case lldb_private::eInstructionTypePrologueEpilogue:
+ return true;
+
+ case lldb_private::eInstructionTypePCModifying:
+ case lldb_private::eInstructionTypeAll:
+ return false;
+ }
+ return false;
+ }
+
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual lldb_private::ConstString
+ GetShortPluginName()
+ {
+ return GetPluginNameStatic();
+ }
+
+ virtual uint32_t
+ GetPluginVersion()
+ {
+ return 1;
+ }
+
+ bool
+ SetTargetTriple (const lldb_private::ArchSpec &arch);
+
+ EmulateInstructionARM64 (const lldb_private::ArchSpec &arch) :
+ EmulateInstruction (arch),
+ m_opcode_pstate (),
+ m_emulated_pstate (),
+ m_ignore_conditions (false)
+ {
+ }
+
+ virtual bool
+ SupportsEmulatingInstructionsOfType (lldb_private::InstructionType inst_type)
+ {
+ return SupportsEmulatingInstructionsOfTypeStatic (inst_type);
+ }
+
+ virtual bool
+ ReadInstruction ();
+
+ virtual bool
+ EvaluateInstruction (uint32_t evaluate_options);
+
+ virtual bool
+ TestEmulation (lldb_private::Stream *out_stream,
+ lldb_private::ArchSpec &arch,
+ lldb_private::OptionValueDictionary *test_data)
+ {
+ return false;
+ }
+
+ virtual bool
+ GetRegisterInfo (lldb::RegisterKind reg_kind,
+ uint32_t reg_num,
+ lldb_private::RegisterInfo &reg_info);
+
+ virtual bool
+ CreateFunctionEntryUnwind (lldb_private::UnwindPlan &unwind_plan);
+
+
+ typedef enum
+ {
+ AddrMode_OFF,
+ AddrMode_PRE,
+ AddrMode_POST
+ } AddrMode;
+
+ typedef enum
+ {
+ BranchType_CALL,
+ BranchType_ERET,
+ BranchType_DRET,
+ BranchType_RET,
+ BranchType_JMP
+ } BranchType;
+
+ typedef enum
+ {
+ CountOp_CLZ,
+ CountOp_CLS,
+ CountOp_CNT
+ } CountOp;
+
+ typedef enum
+ {
+ RevOp_RBIT,
+ RevOp_REV16,
+ RevOp_REV32,
+ RevOp_REV64
+ } RevOp;
+
+ typedef enum
+ {
+ BitwiseOp_NOT,
+ BitwiseOp_RBIT
+ } BitwiseOp;
+
+
+ typedef enum
+ {
+ EL0 = 0,
+ EL1 = 1,
+ EL2 = 2,
+ EL3 = 3
+ } ExceptionLevel;
+
+ typedef enum
+ {
+ ExtendType_SXTB,
+ ExtendType_SXTH,
+ ExtendType_SXTW,
+ ExtendType_SXTX,
+ ExtendType_UXTB,
+ ExtendType_UXTH,
+ ExtendType_UXTW,
+ ExtendType_UXTX
+ } ExtendType;
+
+ typedef enum
+ {
+ ExtractType_LEFT,
+ ExtractType_RIGHT
+ } ExtractType;
+
+ typedef enum
+ {
+ LogicalOp_AND,
+ LogicalOp_EOR,
+ LogicalOp_ORR
+ } LogicalOp;
+
+ typedef enum
+ {
+ MemOp_LOAD,
+ MemOp_STORE,
+ MemOp_PREFETCH,
+ MemOp_NOP
+ } MemOp;
+
+ typedef enum
+ {
+ MoveWideOp_N,
+ MoveWideOp_Z,
+ MoveWideOp_K
+ } MoveWideOp;
+
+ typedef enum {
+ ShiftType_LSL,
+ ShiftType_LSR,
+ ShiftType_ASR,
+ ShiftType_ROR
+ } ShiftType;
+
+ typedef enum
+ {
+ SP0 = 0,
+ SPx = 1
+ } StackPointerSelection;
+
+ typedef enum
+ {
+ Unpredictable_WBOVERLAP,
+ Unpredictable_LDPOVERLAP
+ } Unpredictable;
+
+ typedef enum
+ {
+ Constraint_NONE,
+ Constraint_UNKNOWN,
+ Constraint_SUPPRESSWB,
+ Constraint_NOP
+ } ConstraintType;
+
+ typedef enum
+ {
+ AccType_NORMAL,
+ AccType_UNPRIV,
+ AccType_STREAM,
+ AccType_ALIGNED,
+ AccType_ORDERED
+ } AccType;
+
+ typedef struct
+ {
+ uint32_t
+ N:1,
+ V:1,
+ C:1,
+ Z:1, // condition code flags – can also be accessed as PSTATE.[N,Z,C,V]
+ Q:1, // AArch32 only – CSPR.Q bit
+ IT:8, // AArch32 only – CPSR.IT bits
+ J:1, // AArch32 only – CSPR.J bit
+ T:1, // AArch32 only – CPSR.T bit
+ SS:1, // Single step process state bit
+ IL:1, // Illegal state bit
+ D:1,
+ A:1,
+ I:1,
+ F:1, // Interrupt masks – can also be accessed as PSTATE.[D,A,I,F]
+ E:1, // AArch32 only – CSPR.E bit
+ M:5, // AArch32 only – mode encodings
+ RW:1, // Current register width – 0 is AArch64, 1 is AArch32
+ EL:2, // Current exception level (see ExceptionLevel enum)
+ SP:1; // AArch64 only - Stack Pointer selection (see StackPointerSelection enum)
+ } ProcState;
+
+protected:
+
+ typedef struct
+ {
+ uint32_t mask;
+ uint32_t value;
+ uint32_t vfp_variants;
+ bool (EmulateInstructionARM64::*callback) (const uint32_t opcode);
+ const char *name;
+ } Opcode;
+
+ static Opcode*
+ GetOpcodeForInstruction (const uint32_t opcode);
+
+ bool
+ Emulate_addsub_imm (const uint32_t opcode);
+
+// bool
+// Emulate_STP_Q_ldstpair_off (const uint32_t opcode);
+//
+// bool
+// Emulate_STP_S_ldstpair_off (const uint32_t opcode);
+//
+// bool
+// Emulate_STP_32_ldstpair_off (const uint32_t opcode);
+//
+// bool
+// Emulate_STP_D_ldstpair_off (const uint32_t opcode);
+//
+ bool
+ Emulate_ldstpair_off (const uint32_t opcode);
+
+ bool
+ Emulate_ldstpair_pre (const uint32_t opcode);
+
+ bool
+ Emulate_ldstpair (const uint32_t opcode, AddrMode a_mode);
+
+ ProcState m_opcode_pstate;
+ ProcState m_emulated_pstate; // This can get updated by the opcode.
+ bool m_ignore_conditions;
+};
+
+#endif // EmulateInstructionARM64_h_
diff --git a/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
new file mode 100644
index 000000000000..905984d33410
--- /dev/null
+++ b/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
@@ -0,0 +1,430 @@
+//===-- JITLoaderGDB.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+#include "JITLoaderGDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------
+// Debug Interface Structures
+//------------------------------------------------------------------
+typedef enum
+{
+ JIT_NOACTION = 0,
+ JIT_REGISTER_FN,
+ JIT_UNREGISTER_FN
+} jit_actions_t;
+
+struct jit_code_entry
+{
+ struct jit_code_entry *next_entry;
+ struct jit_code_entry *prev_entry;
+ const char *symfile_addr;
+ uint64_t symfile_size;
+};
+
+struct jit_descriptor
+{
+ uint32_t version;
+ uint32_t action_flag; // Values are jit_action_t
+ struct jit_code_entry *relevant_entry;
+ struct jit_code_entry *first_entry;
+};
+
+JITLoaderGDB::JITLoaderGDB (lldb_private::Process *process) :
+ JITLoader(process),
+ m_jit_objects(),
+ m_jit_break_id(LLDB_INVALID_BREAK_ID),
+ m_jit_descriptor_addr(LLDB_INVALID_ADDRESS)
+{
+}
+
+JITLoaderGDB::~JITLoaderGDB ()
+{
+ if (LLDB_BREAK_ID_IS_VALID(m_jit_break_id))
+ m_process->GetTarget().RemoveBreakpointByID (m_jit_break_id);
+}
+
+void JITLoaderGDB::DidAttach()
+{
+ Target &target = m_process->GetTarget();
+ ModuleList &module_list = target.GetImages();
+ SetJITBreakpoint(module_list);
+}
+
+void JITLoaderGDB::DidLaunch()
+{
+ Target &target = m_process->GetTarget();
+ ModuleList &module_list = target.GetImages();
+ SetJITBreakpoint(module_list);
+}
+
+void
+JITLoaderGDB::ModulesDidLoad(ModuleList &module_list)
+{
+ if (!DidSetJITBreakpoint() && m_process->IsAlive())
+ SetJITBreakpoint(module_list);
+}
+
+//------------------------------------------------------------------
+// Setup the JIT Breakpoint
+//------------------------------------------------------------------
+void
+JITLoaderGDB::SetJITBreakpoint(lldb_private::ModuleList &module_list)
+{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_JIT_LOADER));
+
+ if ( DidSetJITBreakpoint() )
+ return;
+
+ if (log)
+ log->Printf("JITLoaderGDB::%s looking for JIT register hook",
+ __FUNCTION__);
+
+ addr_t jit_addr = GetSymbolAddress(module_list,
+ ConstString("__jit_debug_register_code"),
+ eSymbolTypeAny);
+ if (jit_addr == LLDB_INVALID_ADDRESS)
+ return;
+
+ m_jit_descriptor_addr = GetSymbolAddress(module_list,
+ ConstString("__jit_debug_descriptor"),
+ eSymbolTypeData);
+ if (m_jit_descriptor_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf(
+ "JITLoaderGDB::%s failed to find JIT descriptor address",
+ __FUNCTION__);
+ return;
+ }
+
+ if (log)
+ log->Printf("JITLoaderGDB::%s setting JIT breakpoint",
+ __FUNCTION__);
+
+ Breakpoint *bp =
+ m_process->GetTarget().CreateBreakpoint(jit_addr, true, false).get();
+ bp->SetCallback(JITDebugBreakpointHit, this, true);
+ bp->SetBreakpointKind("jit-debug-register");
+ m_jit_break_id = bp->GetID();
+
+ ReadJITDescriptor(true);
+}
+
+bool
+JITLoaderGDB::JITDebugBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ user_id_t break_id, user_id_t break_loc_id)
+{
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_JIT_LOADER));
+ if (log)
+ log->Printf("JITLoaderGDB::%s hit JIT breakpoint",
+ __FUNCTION__);
+ JITLoaderGDB *instance = static_cast<JITLoaderGDB *>(baton);
+ return instance->ReadJITDescriptor(false);
+}
+
+static void updateSectionLoadAddress(const SectionList &section_list,
+ Target &target,
+ uint64_t symbolfile_addr,
+ uint64_t symbolfile_size,
+ uint64_t &vmaddrheuristic,
+ uint64_t &min_addr,
+ uint64_t &max_addr)
+{
+ const uint32_t num_sections = section_list.GetSize();
+ for (uint32_t i = 0; i<num_sections; ++i)
+ {
+ SectionSP section_sp(section_list.GetSectionAtIndex(i));
+ if (section_sp)
+ {
+ if(section_sp->IsFake()) {
+ uint64_t lower = (uint64_t)-1;
+ uint64_t upper = 0;
+ updateSectionLoadAddress(section_sp->GetChildren(), target, symbolfile_addr, symbolfile_size, vmaddrheuristic,
+ lower, upper);
+ if (lower < min_addr)
+ min_addr = lower;
+ if (upper > max_addr)
+ max_addr = upper;
+ const lldb::addr_t slide_amount = lower - section_sp->GetFileAddress();
+ section_sp->Slide(slide_amount, false);
+ section_sp->GetChildren().Slide(-slide_amount, false);
+ section_sp->SetByteSize (upper - lower);
+ } else {
+ vmaddrheuristic += 2<<section_sp->GetLog2Align();
+ uint64_t lower;
+ if (section_sp->GetFileAddress() > vmaddrheuristic)
+ lower = section_sp->GetFileAddress();
+ else {
+ lower = symbolfile_addr+section_sp->GetFileOffset();
+ section_sp->SetFileAddress(symbolfile_addr+section_sp->GetFileOffset());
+ }
+ target.SetSectionLoadAddress(section_sp, lower, true);
+ uint64_t upper = lower + section_sp->GetByteSize();
+ if (lower < min_addr)
+ min_addr = lower;
+ if (upper > max_addr)
+ max_addr = upper;
+ // This is an upper bound, but a good enough heuristic
+ vmaddrheuristic += section_sp->GetByteSize();
+ }
+ }
+ }
+}
+
+bool
+JITLoaderGDB::ReadJITDescriptor(bool all_entries)
+{
+ if (m_jit_descriptor_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_JIT_LOADER));
+ Target &target = m_process->GetTarget();
+ ModuleList &module_list = target.GetImages();
+
+ jit_descriptor jit_desc;
+ const size_t jit_desc_size = sizeof(jit_desc);
+ Error error;
+ size_t bytes_read = m_process->DoReadMemory(
+ m_jit_descriptor_addr, &jit_desc, jit_desc_size, error);
+ if (bytes_read != jit_desc_size || !error.Success())
+ {
+ if (log)
+ log->Printf("JITLoaderGDB::%s failed to read JIT descriptor",
+ __FUNCTION__);
+ return false;
+ }
+
+ jit_actions_t jit_action = (jit_actions_t)jit_desc.action_flag;
+ addr_t jit_relevant_entry = (addr_t)jit_desc.relevant_entry;
+ if (all_entries)
+ {
+ jit_action = JIT_REGISTER_FN;
+ jit_relevant_entry = (addr_t)jit_desc.first_entry;
+ }
+
+ while (jit_relevant_entry != 0)
+ {
+ jit_code_entry jit_entry;
+ const size_t jit_entry_size = sizeof(jit_entry);
+ bytes_read = m_process->DoReadMemory(jit_relevant_entry, &jit_entry, jit_entry_size, error);
+ if (bytes_read != jit_entry_size || !error.Success())
+ {
+ if (log)
+ log->Printf(
+ "JITLoaderGDB::%s failed to read JIT entry at 0x%" PRIx64,
+ __FUNCTION__, jit_relevant_entry);
+ return false;
+ }
+
+ const addr_t &symbolfile_addr = (addr_t)jit_entry.symfile_addr;
+ const size_t &symbolfile_size = (size_t)jit_entry.symfile_size;
+ ModuleSP module_sp;
+
+ if (jit_action == JIT_REGISTER_FN)
+ {
+ if (log)
+ log->Printf(
+ "JITLoaderGDB::%s registering JIT entry at 0x%" PRIx64
+ " (%" PRIu64 " bytes)",
+ __FUNCTION__, symbolfile_addr, (uint64_t) symbolfile_size);
+
+ char jit_name[64];
+ snprintf(jit_name, 64, "JIT(0x%" PRIx64 ")", symbolfile_addr);
+ module_sp = m_process->ReadModuleFromMemory(
+ FileSpec(jit_name, false), symbolfile_addr, symbolfile_size);
+
+ if (module_sp && module_sp->GetObjectFile())
+ {
+ bool changed;
+ m_jit_objects.insert(std::make_pair(symbolfile_addr, module_sp));
+ if (module_sp->GetObjectFile()->GetPluginName() == ConstString("mach-o"))
+ {
+ ObjectFile *image_object_file = module_sp->GetObjectFile();
+ if (image_object_file)
+ {
+ const SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ uint64_t vmaddrheuristic = 0;
+ uint64_t lower = (uint64_t)-1;
+ uint64_t upper = 0;
+ updateSectionLoadAddress(*section_list, target, symbolfile_addr, symbolfile_size,
+ vmaddrheuristic, lower, upper);
+ }
+ }
+ }
+ else
+ {
+ module_sp->SetLoadAddress(target, 0, true, changed);
+ }
+
+ // load the symbol table right away
+ module_sp->GetObjectFile()->GetSymtab();
+
+ module_list.AppendIfNeeded(module_sp);
+
+ ModuleList module_list;
+ module_list.Append(module_sp);
+ target.ModulesDidLoad(module_list);
+ }
+ else
+ {
+ if (log)
+ log->Printf("JITLoaderGDB::%s failed to load module for "
+ "JIT entry at 0x%" PRIx64,
+ __FUNCTION__, symbolfile_addr);
+ }
+ }
+ else if (jit_action == JIT_UNREGISTER_FN)
+ {
+ if (log)
+ log->Printf(
+ "JITLoaderGDB::%s unregistering JIT entry at 0x%" PRIx64,
+ __FUNCTION__, symbolfile_addr);
+
+ JITObjectMap::iterator it = m_jit_objects.find(symbolfile_addr);
+ if (it != m_jit_objects.end())
+ {
+ module_sp = it->second;
+ ObjectFile *image_object_file = module_sp->GetObjectFile();
+ if (image_object_file)
+ {
+ const SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ const uint32_t num_sections = section_list->GetSize();
+ for (uint32_t i = 0; i<num_sections; ++i)
+ {
+ SectionSP section_sp(section_list->GetSectionAtIndex(i));
+ if (section_sp)
+ {
+ target.GetSectionLoadList().SetSectionUnloaded (section_sp);
+ }
+ }
+ }
+ }
+ module_list.Remove(module_sp);
+ m_jit_objects.erase(it);
+ }
+ }
+ else if (jit_action == JIT_NOACTION)
+ {
+ // Nothing to do
+ }
+ else
+ {
+ assert(false && "Unknown jit action");
+ }
+
+ if (all_entries)
+ jit_relevant_entry = (addr_t)jit_entry.next_entry;
+ else
+ jit_relevant_entry = 0;
+ }
+
+ return false; // Continue Running.
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+JITLoaderGDB::GetPluginNameStatic()
+{
+ static ConstString g_name("gdb");
+ return g_name;
+}
+
+JITLoaderSP
+JITLoaderGDB::CreateInstance(Process *process, bool force)
+{
+ JITLoaderSP jit_loader_sp;
+ ArchSpec arch (process->GetTarget().GetArchitecture());
+ if (arch.GetTriple().getVendor() != llvm::Triple::Apple)
+ jit_loader_sp.reset(new JITLoaderGDB(process));
+ return jit_loader_sp;
+}
+
+const char *
+JITLoaderGDB::GetPluginDescriptionStatic()
+{
+ return "JIT loader plug-in that watches for JIT events using the GDB interface.";
+}
+
+lldb_private::ConstString
+JITLoaderGDB::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+JITLoaderGDB::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+JITLoaderGDB::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+JITLoaderGDB::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+bool
+JITLoaderGDB::DidSetJITBreakpoint() const
+{
+ return LLDB_BREAK_ID_IS_VALID(m_jit_break_id);
+}
+
+addr_t
+JITLoaderGDB::GetSymbolAddress(ModuleList &module_list, const ConstString &name,
+ SymbolType symbol_type) const
+{
+ SymbolContextList target_symbols;
+ Target &target = m_process->GetTarget();
+
+ if (!module_list.FindSymbolsWithNameAndType(name, symbol_type,
+ target_symbols))
+ return LLDB_INVALID_ADDRESS;
+
+ SymbolContext sym_ctx;
+ target_symbols.GetContextAtIndex(0, sym_ctx);
+
+ const Address *jit_descriptor_addr = &sym_ctx.symbol->GetAddress();
+ if (!jit_descriptor_addr || !jit_descriptor_addr->IsValid())
+ return LLDB_INVALID_ADDRESS;
+
+ const addr_t jit_addr = jit_descriptor_addr->GetLoadAddress(&target);
+ return jit_addr;
+}
diff --git a/source/Plugins/JITLoader/GDB/JITLoaderGDB.h b/source/Plugins/JITLoader/GDB/JITLoaderGDB.h
new file mode 100644
index 000000000000..5fa66b874972
--- /dev/null
+++ b/source/Plugins/JITLoader/GDB/JITLoaderGDB.h
@@ -0,0 +1,104 @@
+//===-- JITLoaderGDB.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_JITLoaderGDB_h_
+#define liblldb_JITLoaderGDB_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+#include <string>
+
+#include "lldb/Target/JITLoader.h"
+#include "lldb/Target/Process.h"
+
+class JITLoaderGDB : public lldb_private::JITLoader
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb::JITLoaderSP
+ CreateInstance (lldb_private::Process *process, bool force);
+
+ JITLoaderGDB (lldb_private::Process *process);
+
+ virtual
+ ~JITLoaderGDB ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ //------------------------------------------------------------------
+ // JITLoader interface
+ //------------------------------------------------------------------
+ virtual void
+ DidAttach ();
+
+ virtual void
+ DidLaunch ();
+
+ virtual void
+ ModulesDidLoad (lldb_private::ModuleList &module_list);
+
+private:
+ lldb::addr_t
+ GetSymbolAddress(lldb_private::ModuleList &module_list,
+ const lldb_private::ConstString &name,
+ lldb::SymbolType symbol_type) const;
+
+ void
+ SetJITBreakpoint(lldb_private::ModuleList &module_list);
+
+ bool
+ DidSetJITBreakpoint() const;
+
+ bool
+ ReadJITDescriptor(bool all_entries);
+
+ static bool
+ JITDebugBreakpointHit(void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ static void
+ ProcessStateChangedCallback(void *baton,
+ lldb_private::Process *process,
+ lldb::StateType state);
+
+ // A collection of in-memory jitted object addresses and their corresponding modules
+ typedef std::map<lldb::addr_t, const lldb::ModuleSP> JITObjectMap;
+ JITObjectMap m_jit_objects;
+
+ lldb::user_id_t m_jit_break_id;
+ lldb::addr_t m_jit_descriptor_addr;
+
+};
+
+#endif
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
index 9781dcb093ac..a6c74f3f1fc4 100644
--- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
@@ -107,7 +107,7 @@ ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,
if (symbol != NULL)
{
const char *name = symbol->GetMangled().GetDemangledName().AsCString();
- if (strstr(name, vtable_demangled_prefix) == name)
+ if (name && strstr(name, vtable_demangled_prefix) == name)
{
Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
@@ -289,7 +289,9 @@ ItaniumABILanguageRuntime::CreateInstance (Process *process, lldb::LanguageType
{
// FIXME: We have to check the process and make sure we actually know that this process supports
// the Itanium ABI.
- if (language == eLanguageTypeC_plus_plus)
+ if (language == eLanguageTypeC_plus_plus ||
+ language == eLanguageTypeC_plus_plus_03 ||
+ language == eLanguageTypeC_plus_plus_11)
return new ItaniumABILanguageRuntime (process);
else
return NULL;
diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
index 32574e3ef2f0..0263c23ce307 100644
--- a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
+++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
@@ -74,6 +74,25 @@ ObjectContainerBSDArchive::Object::Extract (const DataExtractor& data, lldb::off
size_t ar_name_len = 0;
std::string str;
char *err;
+
+
+ // File header
+ //
+ // The common format is as follows.
+ //
+ // Offset Length Name Format
+ // 0 16 File name ASCII right padded with spaces (no spaces allowed in file name)
+ // 16 12 File mod Decimal as cstring right padded with spaces
+ // 28 6 Owner ID Decimal as cstring right padded with spaces
+ // 34 6 Group ID Decimal as cstring right padded with spaces
+ // 40 8 File mode Octal as cstring right padded with spaces
+ // 48 10 File byte size Decimal as cstring right padded with spaces
+ // 58 2 File magic 0x60 0x0A
+
+ // Make sure there is enough data for the file header and bail if not
+ if (!data.ValidOffsetForDataOfSize(offset, 60))
+ return LLDB_INVALID_OFFSET;
+
str.assign ((const char *)data.GetData(&offset, 16), 16);
if (str.find("#1/") == 0)
{
@@ -110,7 +129,11 @@ ObjectContainerBSDArchive::Object::Extract (const DataExtractor& data, lldb::off
{
if (ar_name_len > 0)
{
- str.assign ((const char *)data.GetData(&offset, ar_name_len), ar_name_len);
+ const void *ar_name_ptr = data.GetData(&offset, ar_name_len);
+ // Make sure there was enough data for the string value and bail if not
+ if (ar_name_ptr == NULL)
+ return LLDB_INVALID_OFFSET;
+ str.assign ((const char *)ar_name_ptr, ar_name_len);
ar_name.SetCString (str.c_str());
}
ar_file_offset = offset;
@@ -224,7 +247,7 @@ ObjectContainerBSDArchive::Archive::FindCachedArchive (const FileSpec &file, con
// whose modification time doesn't match. It doesn't make sense
// for us to continue to use this BSD archive since we cache only
// the object info which consists of file time info and also the
- // file offset and file size of any contianed objects. Since
+ // file offset and file size of any contained objects. Since
// this information is now out of date, we won't get the correct
// information if we go and extract the file data, so we should
// remove the old and outdated entry.
@@ -335,7 +358,9 @@ ObjectContainerBSDArchive::CreateInstance
Timer scoped_timer (__PRETTY_FUNCTION__,
"ObjectContainerBSDArchive::CreateInstance (module = %s, file = %p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")",
module_sp->GetFileSpec().GetPath().c_str(),
- file, (uint64_t) file_offset, (uint64_t) length);
+ static_cast<const void*>(file),
+ static_cast<uint64_t>(file_offset),
+ static_cast<uint64_t>(length));
// Map the entire .a file to be sure that we don't lose any data if the file
// gets updated by a new build while this .a file is being used for debugging
@@ -457,11 +482,11 @@ ObjectContainerBSDArchive::ParseHeader ()
void
ObjectContainerBSDArchive::Dump (Stream *s) const
{
- s->Printf("%p: ", this);
+ s->Printf("%p: ", static_cast<const void*>(this));
s->Indent();
const size_t num_archs = GetNumArchitectures();
const size_t num_objects = GetNumObjects();
- s->Printf("ObjectContainerBSDArchive, num_archs = %zu, num_objects = %zu", num_archs, num_objects);
+ s->Printf("ObjectContainerBSDArchive, num_archs = %" PRIu64 ", num_objects = %" PRIu64 "", (uint64_t)num_archs, (uint64_t)num_objects);
uint32_t i;
ArchSpec arch;
s->IndentMore();
diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
index a63a01d7ed7a..f027294b7c57 100644
--- a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
+++ b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
@@ -183,6 +183,12 @@ ELFHeader::GetRelocationJumpSlotType() const
case EM_ARM:
slot = R_ARM_JUMP_SLOT;
break;
+ case EM_HEXAGON:
+ slot = R_HEX_JMP_SLOT;
+ break;
+ case EM_AARCH64:
+ slot = R_AARCH64_JUMP_SLOT;
+ break;
}
return slot;
diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.h b/source/Plugins/ObjectFile/ELF/ELFHeader.h
index aa2c16b6168c..4ea22b51baf7 100644
--- a/source/Plugins/ObjectFile/ELF/ELFHeader.h
+++ b/source/Plugins/ObjectFile/ELF/ELFHeader.h
@@ -353,7 +353,7 @@ struct ELFRel
}
/// Returns the symbol index when the given entry represents a 32-bit
- /// reloction.
+ /// relocation.
static unsigned
RelocSymbol32(const ELFRel &rel)
{
@@ -361,7 +361,7 @@ struct ELFRel
}
/// Returns the symbol index when the given entry represents a 64-bit
- /// reloction.
+ /// relocation.
static unsigned
RelocSymbol64(const ELFRel &rel)
{
@@ -412,7 +412,7 @@ struct ELFRela
}
/// Returns the symbol index when the given entry represents a 32-bit
- /// reloction.
+ /// relocation.
static unsigned
RelocSymbol32(const ELFRela &rela)
{
@@ -420,7 +420,7 @@ struct ELFRela
}
/// Returns the symbol index when the given entry represents a 64-bit
- /// reloction.
+ /// relocation.
static unsigned
RelocSymbol64(const ELFRela &rela)
{
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 335090cc0c36..d86aee78947f 100644
--- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -22,13 +22,16 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
#include "lldb/Symbol/DWARFCallFrameInfo.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
-#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MathExtras.h"
#define CASE_AND_STREAM(s, def, width) \
case def: s->Printf("%-*s", width, #def); break;
@@ -39,6 +42,30 @@ using namespace elf;
using namespace llvm::ELF;
namespace {
+
+// ELF note owner definitions
+const char *const LLDB_NT_OWNER_FREEBSD = "FreeBSD";
+const char *const LLDB_NT_OWNER_GNU = "GNU";
+const char *const LLDB_NT_OWNER_NETBSD = "NetBSD";
+const char *const LLDB_NT_OWNER_CSR = "csr";
+
+// ELF note type definitions
+const elf_word LLDB_NT_FREEBSD_ABI_TAG = 0x01;
+const elf_word LLDB_NT_FREEBSD_ABI_SIZE = 4;
+
+const elf_word LLDB_NT_GNU_ABI_TAG = 0x01;
+const elf_word LLDB_NT_GNU_ABI_SIZE = 16;
+
+const elf_word LLDB_NT_GNU_BUILD_ID_TAG = 0x03;
+
+const elf_word LLDB_NT_NETBSD_ABI_TAG = 0x01;
+const elf_word LLDB_NT_NETBSD_ABI_SIZE = 4;
+
+// GNU ABI note OS constants
+const elf_word LLDB_NT_GNU_ABI_OS_LINUX = 0x00;
+const elf_word LLDB_NT_GNU_ABI_OS_HURD = 0x01;
+const elf_word LLDB_NT_GNU_ABI_OS_SOLARIS = 0x02;
+
//===----------------------------------------------------------------------===//
/// @class ELFRelocation
/// @brief Generic wrapper for ELFRel and ELFRela.
@@ -72,6 +99,18 @@ public:
static unsigned
RelocSymbol64(const ELFRelocation &rel);
+ static unsigned
+ RelocOffset32(const ELFRelocation &rel);
+
+ static unsigned
+ RelocOffset64(const ELFRelocation &rel);
+
+ static unsigned
+ RelocAddend32(const ELFRelocation &rel);
+
+ static unsigned
+ RelocAddend64(const ELFRelocation &rel);
+
private:
typedef llvm::PointerUnion<ELFRel*, ELFRela*> RelocUnion;
@@ -80,9 +119,9 @@ private:
ELFRelocation::ELFRelocation(unsigned type)
{
- if (type == DT_REL)
+ if (type == DT_REL || type == SHT_REL)
reloc = new ELFRel();
- else if (type == DT_RELA)
+ else if (type == DT_RELA || type == SHT_RELA)
reloc = new ELFRela();
else {
assert(false && "unexpected relocation type");
@@ -143,6 +182,42 @@ ELFRelocation::RelocSymbol64(const ELFRelocation &rel)
return ELFRela::RelocSymbol64(*rel.reloc.get<ELFRela*>());
}
+unsigned
+ELFRelocation::RelocOffset32(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return rel.reloc.get<ELFRel*>()->r_offset;
+ else
+ return rel.reloc.get<ELFRela*>()->r_offset;
+}
+
+unsigned
+ELFRelocation::RelocOffset64(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return rel.reloc.get<ELFRel*>()->r_offset;
+ else
+ return rel.reloc.get<ELFRela*>()->r_offset;
+}
+
+unsigned
+ELFRelocation::RelocAddend32(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return 0;
+ else
+ return rel.reloc.get<ELFRela*>()->r_addend;
+}
+
+unsigned
+ELFRelocation::RelocAddend64(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return 0;
+ else
+ return rel.reloc.get<ELFRela*>()->r_addend;
+}
+
} // end anonymous namespace
bool
@@ -183,6 +258,39 @@ ELFNote::Parse(const DataExtractor &data, lldb::offset_t *offset)
return true;
}
+static uint32_t
+kalimbaVariantFromElfFlags(const elf::elf_word e_flags)
+{
+ const uint32_t dsp_rev = e_flags & 0xFF;
+ uint32_t kal_arch_variant = LLDB_INVALID_CPUTYPE;
+ switch(dsp_rev)
+ {
+ // TODO(mg11) Support more variants
+ case 10:
+ kal_arch_variant = 3;
+ break;
+ case 14:
+ kal_arch_variant = 4;
+ break;
+ default:
+ break;
+ }
+ return kal_arch_variant;
+}
+
+static uint32_t
+subTypeFromElfHeader(const elf::ELFHeader& header)
+{
+ return
+ llvm::ELF::EM_CSR_KALIMBA == header.e_machine ?
+ kalimbaVariantFromElfFlags(header.e_flags) :
+ LLDB_INVALID_CPUTYPE;
+}
+
+// Arbitrary constant used as UUID prefix for core files.
+const uint32_t
+ObjectFileELF::g_core_uuid_magic(0xE210C);
+
//------------------------------------------------------------------
// Static methods.
//------------------------------------------------------------------
@@ -261,6 +369,22 @@ ObjectFileELF::CreateMemoryInstance (const lldb::ModuleSP &module_sp,
const lldb::ProcessSP &process_sp,
lldb::addr_t header_addr)
{
+ if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT))
+ {
+ const uint8_t *magic = data_sp->GetBytes();
+ if (ELFHeader::MagicBytesMatch(magic))
+ {
+ unsigned address_size = ELFHeader::AddressSizeInBytes(magic);
+ if (address_size == 4 || address_size == 8)
+ {
+ std::auto_ptr<ObjectFileELF> objfile_ap(new ObjectFileELF(module_sp, data_sp, process_sp, header_addr));
+ ArchSpec spec;
+ if (objfile_ap->GetArchitecture(spec) &&
+ objfile_ap->SetModulesArchitecture(spec))
+ return objfile_ap.release();
+ }
+ }
+ }
return NULL;
}
@@ -284,7 +408,7 @@ ObjectFileELF::MagicBytesMatch (DataBufferSP& data_sp,
* code or tables extracted from it, as desired without restriction.
*/
static uint32_t
-calc_gnu_debuglink_crc32(const void *buf, size_t size)
+calc_crc32(uint32_t crc, const void *buf, size_t size)
{
static const uint32_t g_crc32_tab[] =
{
@@ -333,14 +457,100 @@ calc_gnu_debuglink_crc32(const void *buf, size_t size)
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
const uint8_t *p = (const uint8_t *)buf;
- uint32_t crc;
- crc = ~0U;
+ crc = crc ^ ~0U;
while (size--)
crc = g_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
return crc ^ ~0U;
}
+static uint32_t
+calc_gnu_debuglink_crc32(const void *buf, size_t size)
+{
+ return calc_crc32(0U, buf, size);
+}
+
+uint32_t
+ObjectFileELF::CalculateELFNotesSegmentsCRC32 (const ProgramHeaderColl& program_headers,
+ DataExtractor& object_data)
+{
+ typedef ProgramHeaderCollConstIter Iter;
+
+ uint32_t core_notes_crc = 0;
+
+ for (Iter I = program_headers.begin(); I != program_headers.end(); ++I)
+ {
+ if (I->p_type == llvm::ELF::PT_NOTE)
+ {
+ const elf_off ph_offset = I->p_offset;
+ const size_t ph_size = I->p_filesz;
+
+ DataExtractor segment_data;
+ if (segment_data.SetData(object_data, ph_offset, ph_size) != ph_size)
+ {
+ // The ELF program header contained incorrect data,
+ // probably corefile is incomplete or corrupted.
+ break;
+ }
+
+ core_notes_crc = calc_crc32(core_notes_crc,
+ segment_data.GetDataStart(),
+ segment_data.GetByteSize());
+ }
+ }
+
+ return core_notes_crc;
+}
+
+static const char*
+OSABIAsCString (unsigned char osabi_byte)
+{
+#define _MAKE_OSABI_CASE(x) case x: return #x
+ switch (osabi_byte)
+ {
+ _MAKE_OSABI_CASE(ELFOSABI_NONE);
+ _MAKE_OSABI_CASE(ELFOSABI_HPUX);
+ _MAKE_OSABI_CASE(ELFOSABI_NETBSD);
+ _MAKE_OSABI_CASE(ELFOSABI_GNU);
+ _MAKE_OSABI_CASE(ELFOSABI_HURD);
+ _MAKE_OSABI_CASE(ELFOSABI_SOLARIS);
+ _MAKE_OSABI_CASE(ELFOSABI_AIX);
+ _MAKE_OSABI_CASE(ELFOSABI_IRIX);
+ _MAKE_OSABI_CASE(ELFOSABI_FREEBSD);
+ _MAKE_OSABI_CASE(ELFOSABI_TRU64);
+ _MAKE_OSABI_CASE(ELFOSABI_MODESTO);
+ _MAKE_OSABI_CASE(ELFOSABI_OPENBSD);
+ _MAKE_OSABI_CASE(ELFOSABI_OPENVMS);
+ _MAKE_OSABI_CASE(ELFOSABI_NSK);
+ _MAKE_OSABI_CASE(ELFOSABI_AROS);
+ _MAKE_OSABI_CASE(ELFOSABI_FENIXOS);
+ _MAKE_OSABI_CASE(ELFOSABI_C6000_ELFABI);
+ _MAKE_OSABI_CASE(ELFOSABI_C6000_LINUX);
+ _MAKE_OSABI_CASE(ELFOSABI_ARM);
+ _MAKE_OSABI_CASE(ELFOSABI_STANDALONE);
+ default:
+ return "<unknown-osabi>";
+ }
+#undef _MAKE_OSABI_CASE
+}
+
+static bool
+GetOsFromOSABI (unsigned char osabi_byte, llvm::Triple::OSType &ostype)
+{
+ switch (osabi_byte)
+ {
+ case ELFOSABI_AIX: ostype = llvm::Triple::OSType::AIX; break;
+ case ELFOSABI_FREEBSD: ostype = llvm::Triple::OSType::FreeBSD; break;
+ case ELFOSABI_GNU: ostype = llvm::Triple::OSType::Linux; break;
+ case ELFOSABI_NETBSD: ostype = llvm::Triple::OSType::NetBSD; break;
+ case ELFOSABI_OPENBSD: ostype = llvm::Triple::OSType::OpenBSD; break;
+ case ELFOSABI_SOLARIS: ostype = llvm::Triple::OSType::Solaris; break;
+ default:
+ ostype = llvm::Triple::OSType::UnknownOS;
+ }
+ return ostype != llvm::Triple::OSType::UnknownOS;
+}
+
size_t
ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
lldb::DataBufferSP& data_sp,
@@ -349,6 +559,8 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
lldb::offset_t length,
lldb_private::ModuleSpecList &specs)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MODULES));
+
const size_t initial_count = specs.GetSize();
if (ObjectFileELF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize()))
@@ -362,18 +574,30 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
{
ModuleSpec spec;
spec.GetFileSpec() = file;
+
+ const uint32_t sub_type = subTypeFromElfHeader(header);
spec.GetArchitecture().SetArchitecture(eArchTypeELF,
header.e_machine,
- LLDB_INVALID_CPUTYPE);
+ sub_type);
+
if (spec.GetArchitecture().IsValid())
{
- // We could parse the ABI tag information (in .note, .notes, or .note.ABI-tag) to get the
- // machine information. However, this info isn't guaranteed to exist or be correct. Details:
- // http://refspecs.linuxfoundation.org/LSB_1.2.0/gLSB/noteabitag.html
- // Instead of passing potentially incorrect information down the pipeline, grab
- // the host information and use it.
- spec.GetArchitecture().GetTriple().setOSName (Host::GetOSString().GetCString());
- spec.GetArchitecture().GetTriple().setVendorName(Host::GetVendorString().GetCString());
+ llvm::Triple::OSType ostype;
+ // First try to determine the OS type from the OSABI field in the elf header.
+
+ if (log)
+ log->Printf ("ObjectFileELF::%s file '%s' module OSABI: %s", __FUNCTION__, file.GetPath ().c_str (), OSABIAsCString (header.e_ident[EI_OSABI]));
+ if (GetOsFromOSABI (header.e_ident[EI_OSABI], ostype) && ostype != llvm::Triple::OSType::UnknownOS)
+ {
+ spec.GetArchitecture ().GetTriple ().setOS (ostype);
+
+ // Also clear the vendor so we don't end up with situations like
+ // x86_64-apple-FreeBSD.
+ spec.GetArchitecture ().GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor);
+
+ if (log)
+ log->Printf ("ObjectFileELF::%s file '%s' set ELF module OS type from ELF header OSABI.", __FUNCTION__, file.GetPath ().c_str ());
+ }
// Try to get the UUID from the section list. Usually that's at the end, so
// map the file in if we don't have it already.
@@ -388,16 +612,68 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
std::string gnu_debuglink_file;
SectionHeaderColl section_headers;
lldb_private::UUID &uuid = spec.GetUUID();
- GetSectionHeaderInfo(section_headers, data, header, uuid, gnu_debuglink_file, gnu_debuglink_crc);
+
+ GetSectionHeaderInfo(section_headers, data, header, uuid, gnu_debuglink_file, gnu_debuglink_crc, spec.GetArchitecture ());
+
+ // If the module vendor is not set and the module OS matches this host OS, set the module vendor to the host vendor.
+ llvm::Triple &spec_triple = spec.GetArchitecture ().GetTriple ();
+ if (spec_triple.getVendor () == llvm::Triple::VendorType::UnknownVendor)
+ {
+ const llvm::Triple &host_triple = HostInfo::GetArchitecture().GetTriple();
+ if (spec_triple.getOS () == host_triple.getOS ())
+ spec_triple.setVendor (host_triple.getVendor ());
+ }
+
+ if (log)
+ log->Printf ("ObjectFileELF::%s file '%s' module set to triple: %s (architecture %s)", __FUNCTION__, file.GetPath ().c_str (), spec_triple.getTriple ().c_str (), spec.GetArchitecture ().GetArchitectureName ());
if (!uuid.IsValid())
{
+ uint32_t core_notes_crc = 0;
+
if (!gnu_debuglink_crc)
{
- // Need to map entire file into memory to calculate the crc.
- data_sp = file.MemoryMapFileContents (file_offset, SIZE_MAX);
- data.SetData(data_sp);
- gnu_debuglink_crc = calc_gnu_debuglink_crc32 (data.GetDataStart(), data.GetByteSize());
+ lldb_private::Timer scoped_timer (__PRETTY_FUNCTION__,
+ "Calculating module crc32 %s with size %" PRIu64 " KiB",
+ file.GetLastPathComponent().AsCString(),
+ (file.GetByteSize()-file_offset)/1024);
+
+ // For core files - which usually don't happen to have a gnu_debuglink,
+ // and are pretty bulky - calculating whole contents crc32 would be too much of luxury.
+ // Thus we will need to fallback to something simpler.
+ if (header.e_type == llvm::ELF::ET_CORE)
+ {
+ size_t program_headers_end = header.e_phoff + header.e_phnum * header.e_phentsize;
+ if (program_headers_end > data_sp->GetByteSize())
+ {
+ data_sp = file.MemoryMapFileContents(file_offset, program_headers_end);
+ data.SetData(data_sp);
+ }
+ ProgramHeaderColl program_headers;
+ GetProgramHeaderInfo(program_headers, data, header);
+
+ size_t segment_data_end = 0;
+ for (ProgramHeaderCollConstIter I = program_headers.begin();
+ I != program_headers.end(); ++I)
+ {
+ segment_data_end = std::max<unsigned long long> (I->p_offset + I->p_filesz, segment_data_end);
+ }
+
+ if (segment_data_end > data_sp->GetByteSize())
+ {
+ data_sp = file.MemoryMapFileContents(file_offset, segment_data_end);
+ data.SetData(data_sp);
+ }
+
+ core_notes_crc = CalculateELFNotesSegmentsCRC32 (program_headers, data);
+ }
+ else
+ {
+ // Need to map entire file into memory to calculate the crc.
+ data_sp = file.MemoryMapFileContents (file_offset, SIZE_MAX);
+ data.SetData(data_sp);
+ gnu_debuglink_crc = calc_gnu_debuglink_crc32 (data.GetDataStart(), data.GetByteSize());
+ }
}
if (gnu_debuglink_crc)
{
@@ -405,6 +681,13 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
uint32_t uuidt[4] = { gnu_debuglink_crc, 0, 0, 0 };
uuid.SetBytes (uuidt, sizeof(uuidt));
}
+ else if (core_notes_crc)
+ {
+ // Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make it look different form
+ // .gnu_debuglink crc followed by 4 bytes of note segments crc.
+ uint32_t uuidt[4] = { g_core_uuid_magic, core_notes_crc, 0, 0 };
+ uuid.SetBytes (uuidt, sizeof(uuidt));
+ }
}
specs.Append(spec);
@@ -442,15 +725,38 @@ ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp,
lldb::offset_t length) :
ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset),
m_header(),
+ m_uuid(),
+ m_gnu_debuglink_file(),
+ m_gnu_debuglink_crc(0),
m_program_headers(),
m_section_headers(),
- m_filespec_ap()
+ m_dynamic_symbols(),
+ m_filespec_ap(),
+ m_entry_point_address(),
+ m_arch_spec()
{
if (file)
m_file = *file;
::memset(&m_header, 0, sizeof(m_header));
- m_gnu_debuglink_crc = 0;
- m_gnu_debuglink_file.clear();
+}
+
+ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
+ addr_t header_addr) :
+ ObjectFile(module_sp, process_sp, LLDB_INVALID_ADDRESS, data_sp),
+ m_header(),
+ m_uuid(),
+ m_gnu_debuglink_file(),
+ m_gnu_debuglink_crc(0),
+ m_program_headers(),
+ m_section_headers(),
+ m_dynamic_symbols(),
+ m_filespec_ap(),
+ m_entry_point_address(),
+ m_arch_spec()
+{
+ ::memset(&m_header, 0, sizeof(m_header));
}
ObjectFileELF::~ObjectFileELF()
@@ -460,7 +766,7 @@ ObjectFileELF::~ObjectFileELF()
bool
ObjectFileELF::IsExecutable() const
{
- return m_header.e_entry != 0;
+ return ((m_header.e_type & ET_EXEC) != 0) || (m_header.e_entry != 0);
}
bool
@@ -543,7 +849,7 @@ bool
ObjectFileELF::GetUUID(lldb_private::UUID* uuid)
{
// Need to parse the section list to get the UUIDs, so make sure that's been done.
- if (!ParseSectionHeaders())
+ if (!ParseSectionHeaders() && GetType() != ObjectFile::eTypeCoreFile)
return false;
if (m_uuid.IsValid())
@@ -552,7 +858,25 @@ ObjectFileELF::GetUUID(lldb_private::UUID* uuid)
*uuid = m_uuid;
return true;
}
- else
+ else if (GetType() == ObjectFile::eTypeCoreFile)
+ {
+ uint32_t core_notes_crc = 0;
+
+ if (!ParseProgramHeaders())
+ return false;
+
+ core_notes_crc = CalculateELFNotesSegmentsCRC32(m_program_headers, m_data);
+
+ if (core_notes_crc)
+ {
+ // Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make it
+ // look different form .gnu_debuglink crc - followed by 4 bytes of note
+ // segments crc.
+ uint32_t uuidt[4] = { g_core_uuid_magic, core_notes_crc, 0, 0 };
+ m_uuid.SetBytes (uuidt, sizeof(uuidt));
+ }
+ }
+ else
{
if (!m_gnu_debuglink_crc)
m_gnu_debuglink_crc = calc_gnu_debuglink_crc32 (m_data.GetDataStart(), m_data.GetByteSize());
@@ -560,11 +884,16 @@ ObjectFileELF::GetUUID(lldb_private::UUID* uuid)
{
// Use 4 bytes of crc from the .gnu_debuglink section.
uint32_t uuidt[4] = { m_gnu_debuglink_crc, 0, 0, 0 };
- uuid->SetBytes (uuidt, sizeof(uuidt));
- return true;
+ m_uuid.SetBytes (uuidt, sizeof(uuidt));
}
}
+ if (m_uuid.IsValid())
+ {
+ *uuid = m_uuid;
+ return true;
+ }
+
return false;
}
@@ -724,72 +1053,235 @@ ObjectFileELF::ParseDependentModules()
}
//----------------------------------------------------------------------
-// ParseProgramHeaders
+// GetProgramHeaderInfo
//----------------------------------------------------------------------
size_t
-ObjectFileELF::ParseProgramHeaders()
+ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
+ DataExtractor &object_data,
+ const ELFHeader &header)
{
// We have already parsed the program headers
- if (!m_program_headers.empty())
- return m_program_headers.size();
+ if (!program_headers.empty())
+ return program_headers.size();
// If there are no program headers to read we are done.
- if (m_header.e_phnum == 0)
+ if (header.e_phnum == 0)
return 0;
- m_program_headers.resize(m_header.e_phnum);
- if (m_program_headers.size() != m_header.e_phnum)
+ program_headers.resize(header.e_phnum);
+ if (program_headers.size() != header.e_phnum)
return 0;
- const size_t ph_size = m_header.e_phnum * m_header.e_phentsize;
- const elf_off ph_offset = m_header.e_phoff;
+ const size_t ph_size = header.e_phnum * header.e_phentsize;
+ const elf_off ph_offset = header.e_phoff;
DataExtractor data;
- if (GetData (ph_offset, ph_size, data) != ph_size)
+ if (data.SetData(object_data, ph_offset, ph_size) != ph_size)
return 0;
uint32_t idx;
lldb::offset_t offset;
- for (idx = 0, offset = 0; idx < m_header.e_phnum; ++idx)
+ for (idx = 0, offset = 0; idx < header.e_phnum; ++idx)
{
- if (m_program_headers[idx].Parse(data, &offset) == false)
+ if (program_headers[idx].Parse(data, &offset) == false)
break;
}
- if (idx < m_program_headers.size())
- m_program_headers.resize(idx);
+ if (idx < program_headers.size())
+ program_headers.resize(idx);
+
+ return program_headers.size();
- return m_program_headers.size();
}
-static bool
-ParseNoteGNUBuildID(DataExtractor &data, lldb_private::UUID &uuid)
+//----------------------------------------------------------------------
+// ParseProgramHeaders
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::ParseProgramHeaders()
+{
+ return GetProgramHeaderInfo(m_program_headers, m_data, m_header);
+}
+
+lldb_private::Error
+ObjectFileELF::RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch_spec, lldb_private::UUID &uuid)
{
- // Try to parse the note section (ie .note.gnu.build-id|.notes|.note|...) and get the build id.
- // BuildID documentation: https://fedoraproject.org/wiki/Releases/FeatureBuildId
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MODULES));
+ Error error;
+
lldb::offset_t offset = 0;
- static const uint32_t g_gnu_build_id = 3; // NT_GNU_BUILD_ID from elf.h
while (true)
{
+ // Parse the note header. If this fails, bail out.
ELFNote note = ELFNote();
if (!note.Parse(data, &offset))
- return false;
+ {
+ // We're done.
+ return error;
+ }
+
+ // If a tag processor handles the tag, it should set processed to true, and
+ // the loop will assume the tag processing has moved entirely past the note's payload.
+ // Otherwise, leave it false and the end of the loop will handle the offset properly.
+ bool processed = false;
- // 16 bytes is UUID|MD5, 20 bytes is SHA1
- if (note.n_name == "GNU" && (note.n_type == g_gnu_build_id) &&
- (note.n_descsz == 16 || note.n_descsz == 20))
+ if (log)
+ log->Printf ("ObjectFileELF::%s parsing note name='%s', type=%" PRIu32, __FUNCTION__, note.n_name.c_str (), note.n_type);
+
+ // Process FreeBSD ELF notes.
+ if ((note.n_name == LLDB_NT_OWNER_FREEBSD) &&
+ (note.n_type == LLDB_NT_FREEBSD_ABI_TAG) &&
+ (note.n_descsz == LLDB_NT_FREEBSD_ABI_SIZE))
{
- uint8_t uuidbuf[20];
- if (data.GetU8 (&offset, &uuidbuf, note.n_descsz) == NULL)
- return false;
- uuid.SetBytes (uuidbuf, note.n_descsz);
- return true;
+ // We'll consume the payload below.
+ processed = true;
+
+ // Pull out the min version info.
+ uint32_t version_info;
+ if (data.GetU32 (&offset, &version_info, 1) == nullptr)
+ {
+ error.SetErrorString ("failed to read FreeBSD ABI note payload");
+ return error;
+ }
+
+ // Convert the version info into a major/minor number.
+ const uint32_t version_major = version_info / 100000;
+ const uint32_t version_minor = (version_info / 1000) % 100;
+
+ char os_name[32];
+ snprintf (os_name, sizeof (os_name), "freebsd%" PRIu32 ".%" PRIu32, version_major, version_minor);
+
+ // Set the elf OS version to FreeBSD. Also clear the vendor.
+ arch_spec.GetTriple ().setOSName (os_name);
+ arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor);
+
+ if (log)
+ log->Printf ("ObjectFileELF::%s detected FreeBSD %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_major, version_minor, static_cast<uint32_t> (version_info % 1000));
+ }
+ // Process GNU ELF notes.
+ else if (note.n_name == LLDB_NT_OWNER_GNU)
+ {
+ switch (note.n_type)
+ {
+ case LLDB_NT_GNU_ABI_TAG:
+ if (note.n_descsz == LLDB_NT_GNU_ABI_SIZE)
+ {
+ // We'll consume the payload below.
+ processed = true;
+
+ // Pull out the min OS version supporting the ABI.
+ uint32_t version_info[4];
+ if (data.GetU32 (&offset, &version_info[0], note.n_descsz / 4) == nullptr)
+ {
+ error.SetErrorString ("failed to read GNU ABI note payload");
+ return error;
+ }
+
+ // Set the OS per the OS field.
+ switch (version_info[0])
+ {
+ case LLDB_NT_GNU_ABI_OS_LINUX:
+ arch_spec.GetTriple ().setOS (llvm::Triple::OSType::Linux);
+ arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor);
+ if (log)
+ log->Printf ("ObjectFileELF::%s detected Linux, min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[1], version_info[2], version_info[3]);
+ // FIXME we have the minimal version number, we could be propagating that. version_info[1] = OS Major, version_info[2] = OS Minor, version_info[3] = Revision.
+ break;
+ case LLDB_NT_GNU_ABI_OS_HURD:
+ arch_spec.GetTriple ().setOS (llvm::Triple::OSType::UnknownOS);
+ arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor);
+ if (log)
+ log->Printf ("ObjectFileELF::%s detected Hurd (unsupported), min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[1], version_info[2], version_info[3]);
+ break;
+ case LLDB_NT_GNU_ABI_OS_SOLARIS:
+ arch_spec.GetTriple ().setOS (llvm::Triple::OSType::Solaris);
+ arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor);
+ if (log)
+ log->Printf ("ObjectFileELF::%s detected Solaris, min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[1], version_info[2], version_info[3]);
+ break;
+ default:
+ if (log)
+ log->Printf ("ObjectFileELF::%s unrecognized OS in note, id %" PRIu32 ", min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[0], version_info[1], version_info[2], version_info[3]);
+ break;
+ }
+ }
+ break;
+
+ case LLDB_NT_GNU_BUILD_ID_TAG:
+ // Only bother processing this if we don't already have the uuid set.
+ if (!uuid.IsValid())
+ {
+ // We'll consume the payload below.
+ processed = true;
+
+ // 16 bytes is UUID|MD5, 20 bytes is SHA1
+ if ((note.n_descsz == 16 || note.n_descsz == 20))
+ {
+ uint8_t uuidbuf[20];
+ if (data.GetU8 (&offset, &uuidbuf, note.n_descsz) == nullptr)
+ {
+ error.SetErrorString ("failed to read GNU_BUILD_ID note payload");
+ return error;
+ }
+
+ // Save the build id as the UUID for the module.
+ uuid.SetBytes (uuidbuf, note.n_descsz);
+ }
+ }
+ break;
+ }
}
- offset += llvm::RoundUpToAlignment(note.n_descsz, 4);
+ // Process NetBSD ELF notes.
+ else if ((note.n_name == LLDB_NT_OWNER_NETBSD) &&
+ (note.n_type == LLDB_NT_NETBSD_ABI_TAG) &&
+ (note.n_descsz == LLDB_NT_NETBSD_ABI_SIZE))
+ {
+
+ // We'll consume the payload below.
+ processed = true;
+
+ // Pull out the min version info.
+ uint32_t version_info;
+ if (data.GetU32 (&offset, &version_info, 1) == nullptr)
+ {
+ error.SetErrorString ("failed to read NetBSD ABI note payload");
+ return error;
+ }
+
+ // Set the elf OS version to NetBSD. Also clear the vendor.
+ arch_spec.GetTriple ().setOS (llvm::Triple::OSType::NetBSD);
+ arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor);
+
+ if (log)
+ log->Printf ("ObjectFileELF::%s detected NetBSD, min version constant %" PRIu32, __FUNCTION__, version_info);
+ }
+ // Process CSR kalimba notes
+ else if ((note.n_type == LLDB_NT_GNU_ABI_TAG) &&
+ (note.n_name == LLDB_NT_OWNER_CSR))
+ {
+ // We'll consume the payload below.
+ processed = true;
+ arch_spec.GetTriple().setOS(llvm::Triple::OSType::UnknownOS);
+ arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::CSR);
+
+ // TODO At some point the description string could be processed.
+ // It could provide a steer towards the kalimba variant which
+ // this ELF targets.
+ if(note.n_descsz)
+ {
+ const char *cstr = data.GetCStr(&offset, llvm::RoundUpToAlignment (note.n_descsz, 4));
+ (void)cstr;
+ }
+ }
+
+ if (!processed)
+ offset += llvm::RoundUpToAlignment(note.n_descsz, 4);
}
- return false;
+
+ return error;
}
+
//----------------------------------------------------------------------
// GetSectionHeaderInfo
//----------------------------------------------------------------------
@@ -799,16 +1291,51 @@ ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
const elf::ELFHeader &header,
lldb_private::UUID &uuid,
std::string &gnu_debuglink_file,
- uint32_t &gnu_debuglink_crc)
+ uint32_t &gnu_debuglink_crc,
+ ArchSpec &arch_spec)
{
- // We have already parsed the section headers
+ // Don't reparse the section headers if we already did that.
if (!section_headers.empty())
return section_headers.size();
+ // Only initialize the arch_spec to okay defaults if they're not already set.
+ // We'll refine this with note data as we parse the notes.
+ if (arch_spec.GetTriple ().getOS () == llvm::Triple::OSType::UnknownOS)
+ {
+ const uint32_t sub_type = subTypeFromElfHeader(header);
+ arch_spec.SetArchitecture (eArchTypeELF, header.e_machine, sub_type);
+
+ switch (arch_spec.GetAddressByteSize())
+ {
+ case 4:
+ {
+ const ArchSpec host_arch32 = HostInfo::GetArchitecture(HostInfo::eArchKind32);
+ if (host_arch32.GetCore() == arch_spec.GetCore())
+ {
+ arch_spec.GetTriple().setOSName(HostInfo::GetOSString().data());
+ arch_spec.GetTriple().setVendorName(HostInfo::GetVendorString().data());
+ }
+ }
+ break;
+ case 8:
+ {
+ const ArchSpec host_arch64 = HostInfo::GetArchitecture(HostInfo::eArchKind64);
+ if (host_arch64.GetCore() == arch_spec.GetCore())
+ {
+ arch_spec.GetTriple().setOSName(HostInfo::GetOSString().data());
+ arch_spec.GetTriple().setVendorName(HostInfo::GetVendorString().data());
+ }
+ }
+ break;
+ }
+ }
+
// If there are no section headers we are done.
if (header.e_shnum == 0)
return 0;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MODULES));
+
section_headers.resize(header.e_shnum);
if (section_headers.size() != header.e_shnum)
return 0;
@@ -861,12 +1388,19 @@ ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
}
}
- if (header.sh_type == SHT_NOTE && !uuid.IsValid())
+ // Process ELF note section entries.
+ if (header.sh_type == SHT_NOTE)
{
+ // Allow notes to refine module info.
DataExtractor data;
if (section_size && (data.SetData (object_data, header.sh_offset, section_size) == section_size))
{
- ParseNoteGNUBuildID (data, uuid);
+ Error error = RefineModuleDetailsFromNote (data, arch_spec, uuid);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("ObjectFileELF::%s ELF note processing failed: %s", __FUNCTION__, error.AsCString ());
+ }
}
}
}
@@ -912,7 +1446,7 @@ ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id)
size_t
ObjectFileELF::ParseSectionHeaders()
{
- return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc);
+ return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc, m_arch_spec);
}
const ObjectFileELF::ELFSectionHeaderInfo *
@@ -1026,6 +1560,9 @@ ObjectFileELF::CreateSections(SectionList &unified_section_list)
break;
}
+ elf::elf_xword log2align = (header.sh_addralign==0)
+ ? 0
+ : llvm::Log2_64(header.sh_addralign);
SectionSP section_sp (new Section(GetModule(), // Module to which this section belongs.
this, // ObjectFile to which this section belongs and should read section data from.
SectionIndex(I), // Section ID.
@@ -1035,6 +1572,7 @@ ObjectFileELF::CreateSections(SectionList &unified_section_list)
vm_size, // VM size in bytes of this section.
header.sh_offset, // Offset of this section in the file.
file_size, // Size of the section as found in the file.
+ log2align, // Alignment of the section
header.sh_flags)); // Flags for this section.
if (is_thread_specific)
@@ -1117,8 +1655,9 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
const char *symbol_name = strtab_data.PeekCStr(symbol.st_name);
- // No need to add symbols that have no names
- if (symbol_name == NULL || symbol_name[0] == '\0')
+ // No need to add non-section symbols that have no names
+ if (symbol.getType() != STT_SECTION &&
+ (symbol_name == NULL || symbol_name[0] == '\0'))
continue;
//symbol.Dump (&strm, i, &strtab_data, section_list);
@@ -1228,7 +1767,7 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
}
uint64_t symbol_value = symbol.st_value;
- if (symbol_section_sp)
+ if (symbol_section_sp && CalculateType() != ObjectFile::Type::eTypeObjectFile)
symbol_value -= symbol_section_sp->GetFileAddress();
bool is_global = symbol.getBinding() == STB_GLOBAL;
uint32_t flags = symbol.st_other << 8 | symbol.st_info;
@@ -1279,7 +1818,6 @@ ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, user_id_t start_id, lldb_p
user_id_t strtab_id = symtab_hdr->sh_link + 1;
Section *strtab = section_list->FindSectionByID(strtab_id).get();
- unsigned num_symbols = 0;
if (symtab && strtab)
{
assert (symtab->GetObjectFile() == this);
@@ -1292,13 +1830,12 @@ ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, user_id_t start_id, lldb_p
{
size_t num_symbols = symtab_data.GetByteSize() / symtab_hdr->sh_entsize;
- num_symbols = ParseSymbols(symbol_table, start_id,
- section_list, num_symbols,
- symtab_data, strtab_data);
+ return ParseSymbols(symbol_table, start_id, section_list,
+ num_symbols, symtab_data, strtab_data);
}
}
- return num_symbols;
+ return 0;
}
size_t
@@ -1526,6 +2063,136 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table,
strtab_data);
}
+unsigned
+ObjectFileELF::RelocateSection(Symtab* symtab, const ELFHeader *hdr, const ELFSectionHeader *rel_hdr,
+ const ELFSectionHeader *symtab_hdr, const ELFSectionHeader *debug_hdr,
+ DataExtractor &rel_data, DataExtractor &symtab_data,
+ DataExtractor &debug_data, Section* rel_section)
+{
+ ELFRelocation rel(rel_hdr->sh_type);
+ lldb::addr_t offset = 0;
+ const unsigned num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize;
+ typedef unsigned (*reloc_info_fn)(const ELFRelocation &rel);
+ reloc_info_fn reloc_type;
+ reloc_info_fn reloc_symbol;
+
+ if (hdr->Is32Bit())
+ {
+ reloc_type = ELFRelocation::RelocType32;
+ reloc_symbol = ELFRelocation::RelocSymbol32;
+ }
+ else
+ {
+ reloc_type = ELFRelocation::RelocType64;
+ reloc_symbol = ELFRelocation::RelocSymbol64;
+ }
+
+ for (unsigned i = 0; i < num_relocations; ++i)
+ {
+ if (rel.Parse(rel_data, &offset) == false)
+ break;
+
+ Symbol* symbol = NULL;
+
+ if (hdr->Is32Bit())
+ {
+ switch (reloc_type(rel)) {
+ case R_386_32:
+ case R_386_PC32:
+ default:
+ assert(false && "unexpected relocation type");
+ }
+ } else {
+ switch (reloc_type(rel)) {
+ case R_X86_64_64:
+ {
+ symbol = symtab->FindSymbolByID(reloc_symbol(rel));
+ if (symbol)
+ {
+ addr_t value = symbol->GetAddress().GetFileAddress();
+ DataBufferSP& data_buffer_sp = debug_data.GetSharedDataBuffer();
+ uint64_t* dst = reinterpret_cast<uint64_t*>(data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset64(rel));
+ *dst = value + ELFRelocation::RelocAddend64(rel);
+ }
+ break;
+ }
+ case R_X86_64_32:
+ case R_X86_64_32S:
+ {
+ symbol = symtab->FindSymbolByID(reloc_symbol(rel));
+ if (symbol)
+ {
+ addr_t value = symbol->GetAddress().GetFileAddress();
+ value += ELFRelocation::RelocAddend32(rel);
+ assert((reloc_type(rel) == R_X86_64_32 && (value <= UINT32_MAX)) ||
+ (reloc_type(rel) == R_X86_64_32S &&
+ ((int64_t)value <= INT32_MAX && (int64_t)value >= INT32_MIN)));
+ uint32_t truncated_addr = (value & 0xFFFFFFFF);
+ DataBufferSP& data_buffer_sp = debug_data.GetSharedDataBuffer();
+ uint32_t* dst = reinterpret_cast<uint32_t*>(data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset32(rel));
+ *dst = truncated_addr;
+ }
+ break;
+ }
+ case R_X86_64_PC32:
+ default:
+ assert(false && "unexpected relocation type");
+ }
+ }
+ }
+
+ return 0;
+}
+
+unsigned
+ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, user_id_t rel_id)
+{
+ assert(rel_hdr->sh_type == SHT_RELA || rel_hdr->sh_type == SHT_REL);
+
+ // Parse in the section list if needed.
+ SectionList *section_list = GetSectionList();
+ if (!section_list)
+ return 0;
+
+ // Section ID's are ones based.
+ user_id_t symtab_id = rel_hdr->sh_link + 1;
+ user_id_t debug_id = rel_hdr->sh_info + 1;
+
+ const ELFSectionHeader *symtab_hdr = GetSectionHeaderByIndex(symtab_id);
+ if (!symtab_hdr)
+ return 0;
+
+ const ELFSectionHeader *debug_hdr = GetSectionHeaderByIndex(debug_id);
+ if (!debug_hdr)
+ return 0;
+
+ Section *rel = section_list->FindSectionByID(rel_id).get();
+ if (!rel)
+ return 0;
+
+ Section *symtab = section_list->FindSectionByID(symtab_id).get();
+ if (!symtab)
+ return 0;
+
+ Section *debug = section_list->FindSectionByID(debug_id).get();
+ if (!debug)
+ return 0;
+
+ DataExtractor rel_data;
+ DataExtractor symtab_data;
+ DataExtractor debug_data;
+
+ if (ReadSectionData(rel, rel_data) &&
+ ReadSectionData(symtab, symtab_data) &&
+ ReadSectionData(debug, debug_data))
+ {
+ RelocateSection(m_symtab_ap.get(), &m_header, rel_hdr, symtab_hdr, debug_hdr,
+ rel_data, symtab_data, debug_data, debug);
+ }
+
+ return 0;
+}
+
Symtab *
ObjectFileELF::GetSymtab()
{
@@ -1588,6 +2255,25 @@ ObjectFileELF::GetSymtab()
}
}
}
+
+ for (SectionHeaderCollIter I = m_section_headers.begin();
+ I != m_section_headers.end(); ++I)
+ {
+ if (I->sh_type == SHT_RELA || I->sh_type == SHT_REL)
+ {
+ if (CalculateType() == eTypeObjectFile)
+ {
+ const char *section_name = I->section_name.AsCString("");
+ if (strstr(section_name, ".rela.debug") ||
+ strstr(section_name, ".rel.debug"))
+ {
+ const ELFSectionHeader &reloc_header = *I;
+ user_id_t reloc_id = SectionIndex(I);
+ RelocateDebugSections(&reloc_header, reloc_id);
+ }
+ }
+ }
+ }
return m_symtab_ap.get();
}
@@ -1958,9 +2644,13 @@ ObjectFileELF::GetArchitecture (ArchSpec &arch)
if (!ParseHeader())
return false;
- arch.SetArchitecture (eArchTypeELF, m_header.e_machine, LLDB_INVALID_CPUTYPE);
- arch.GetTriple().setOSName (Host::GetOSString().GetCString());
- arch.GetTriple().setVendorName(Host::GetVendorString().GetCString());
+ if (m_section_headers.empty())
+ {
+ // Allow elf notes to be parsed which may affect the detected architecture.
+ ParseSectionHeaders();
+ }
+
+ arch = m_arch_spec;
return true;
}
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index 9b7c073d902d..6b036af7aeff 100644
--- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -17,6 +17,7 @@
#include "lldb/Host/FileSpec.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Core/UUID.h"
+#include "lldb/Core/ArchSpec.h"
#include "ELFHeader.h"
@@ -191,6 +192,11 @@ private:
lldb::offset_t offset,
lldb::offset_t length);
+ ObjectFileELF (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr);
+
typedef std::vector<elf::ELFProgramHeader> ProgramHeaderColl;
typedef ProgramHeaderColl::iterator ProgramHeaderCollIter;
typedef ProgramHeaderColl::const_iterator ProgramHeaderCollConstIter;
@@ -209,6 +215,7 @@ private:
/// Version of this reader common to all plugins based on this class.
static const uint32_t m_plugin_version = 1;
+ static const uint32_t g_core_uuid_magic;
/// ELF file header.
elf::ELFHeader m_header;
@@ -236,6 +243,9 @@ private:
/// Cached value of the entry point for this module.
lldb_private::Address m_entry_point_address;
+ /// The architecture detected from parsing elf file contents.
+ lldb_private::ArchSpec m_arch_spec;
+
/// Returns a 1 based index of the given section header.
size_t
SectionIndex(const SectionHeaderCollIter &I);
@@ -244,6 +254,17 @@ private:
size_t
SectionIndex(const SectionHeaderCollConstIter &I) const;
+ // Parses the ELF program headers.
+ static size_t
+ GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
+ lldb_private::DataExtractor &data,
+ const elf::ELFHeader &header);
+
+ // Finds PT_NOTE segments and calculates their crc sum.
+ static uint32_t
+ CalculateELFNotesSegmentsCRC32(const ProgramHeaderColl& program_headers,
+ lldb_private::DataExtractor &data);
+
/// Parses all section headers present in this object file and populates
/// m_program_headers. This method will compute the header list only once.
/// Returns the number of headers parsed.
@@ -256,14 +277,15 @@ private:
size_t
ParseSectionHeaders();
- /// Parses the elf section headers and returns the uuid, debug link name, crc.
+ /// Parses the elf section headers and returns the uuid, debug link name, crc, archspec.
static size_t
GetSectionHeaderInfo(SectionHeaderColl &section_headers,
lldb_private::DataExtractor &data,
const elf::ELFHeader &header,
lldb_private::UUID &uuid,
std::string &gnu_debuglink_file,
- uint32_t &gnu_debuglink_crc);
+ uint32_t &gnu_debuglink_crc,
+ lldb_private::ArchSpec &arch_spec);
/// Scans the dynamic section and locates all dependent modules (shared
/// libraries) populating m_filespec_ap. This method will compute the
@@ -303,6 +325,32 @@ private:
const ELFSectionHeaderInfo *rela_hdr,
lldb::user_id_t section_id);
+ /// Relocates debug sections
+ unsigned
+ RelocateDebugSections(const elf::ELFSectionHeader *rel_hdr, lldb::user_id_t rel_id);
+
+ unsigned
+ RelocateSection(lldb_private::Symtab* symtab, const elf::ELFHeader *hdr, const elf::ELFSectionHeader *rel_hdr,
+ const elf::ELFSectionHeader *symtab_hdr, const elf::ELFSectionHeader *debug_hdr,
+ lldb_private::DataExtractor &rel_data, lldb_private::DataExtractor &symtab_data,
+ lldb_private::DataExtractor &debug_data, lldb_private::Section* rel_section);
+
+ /// Loads the section name string table into m_shstr_data. Returns the
+ /// number of bytes constituting the table.
+ size_t
+ GetSectionHeaderStringTable();
+
+ /// Utility method for looking up a section given its name. Returns the
+ /// index of the corresponding section or zero if no section with the given
+ /// name can be found (note that section indices are always 1 based, and so
+ /// section index 0 is never valid).
+ lldb::user_id_t
+ GetSectionIndexByName(const char *name);
+
+ // Returns the ID of the first section that has the given type.
+ lldb::user_id_t
+ GetSectionIndexByType(unsigned type);
+
/// Returns the section header with the given id or NULL.
const ELFSectionHeaderInfo *
GetSectionHeaderByIndex(lldb::user_id_t id);
@@ -364,6 +412,9 @@ private:
unsigned
PLTRelocationType();
+
+ static lldb_private::Error
+ RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch_spec, lldb_private::UUID &uuid);
};
#endif // #ifndef liblldb_ObjectFileELF_h_
diff --git a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp
new file mode 100644
index 000000000000..5498bed13ebc
--- /dev/null
+++ b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp
@@ -0,0 +1,363 @@
+//===-- ObjectFileJIT.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringRef.h"
+
+#include "ObjectFileJIT.h"
+
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+
+#ifndef __APPLE__
+#include "Utility/UuidCompatibility.h"
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+void
+ObjectFileJIT::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ CreateMemoryInstance,
+ GetModuleSpecifications);
+}
+
+void
+ObjectFileJIT::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+ObjectFileJIT::GetPluginNameStatic()
+{
+ static ConstString g_name("jit");
+ return g_name;
+}
+
+const char *
+ObjectFileJIT::GetPluginDescriptionStatic()
+{
+ return "JIT code object file";
+}
+
+ObjectFile *
+ObjectFileJIT::CreateInstance (const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length)
+{
+ // JIT'ed object file is backed by the ObjectFileJITDelegate, never
+ // read from a file
+ return NULL;
+}
+
+ObjectFile *
+ObjectFileJIT::CreateMemoryInstance (const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ const ProcessSP &process_sp,
+ lldb::addr_t header_addr)
+{
+ // JIT'ed object file is backed by the ObjectFileJITDelegate, never
+ // read from memory
+ return NULL;
+}
+
+size_t
+ObjectFileJIT::GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb_private::ModuleSpecList &specs)
+{
+ // JIT'ed object file can't be read from a file on disk
+ return 0;
+}
+
+ObjectFileJIT::ObjectFileJIT (const lldb::ModuleSP &module_sp,
+ const ObjectFileJITDelegateSP &delegate_sp) :
+ ObjectFile(module_sp, NULL, 0, 0, DataBufferSP(), 0),
+ m_delegate_wp ()
+{
+ if (delegate_sp)
+ {
+ m_delegate_wp = delegate_sp;
+ m_data.SetByteOrder(delegate_sp->GetByteOrder());
+ m_data.SetAddressByteSize(delegate_sp->GetAddressByteSize());
+ }
+}
+
+ObjectFileJIT::~ObjectFileJIT()
+{
+}
+
+
+bool
+ObjectFileJIT::ParseHeader ()
+{
+ // JIT code is never in a file, nor is it required to have any header
+ return false;
+}
+
+ByteOrder
+ObjectFileJIT::GetByteOrder () const
+{
+ return m_data.GetByteOrder();
+}
+
+bool
+ObjectFileJIT::IsExecutable() const
+{
+ return false;
+}
+
+uint32_t
+ObjectFileJIT::GetAddressByteSize () const
+{
+ return m_data.GetAddressByteSize();
+}
+
+
+Symtab *
+ObjectFileJIT::GetSymtab()
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_symtab_ap.get() == NULL)
+ {
+ m_symtab_ap.reset(new Symtab(this));
+ Mutex::Locker symtab_locker (m_symtab_ap->GetMutex());
+ ObjectFileJITDelegateSP delegate_sp (m_delegate_wp.lock());
+ if (delegate_sp)
+ delegate_sp->PopulateSymtab(this, *m_symtab_ap);
+ // TODO: get symbols from delegate
+ m_symtab_ap->Finalize ();
+ }
+ }
+ return m_symtab_ap.get();
+}
+
+bool
+ObjectFileJIT::IsStripped ()
+{
+ return false; // JIT code that is in a module is never stripped
+}
+
+void
+ObjectFileJIT::CreateSections (SectionList &unified_section_list)
+{
+ if (!m_sections_ap.get())
+ {
+ m_sections_ap.reset(new SectionList());
+ ObjectFileJITDelegateSP delegate_sp (m_delegate_wp.lock());
+ if (delegate_sp)
+ {
+ delegate_sp->PopulateSectionList(this, *m_sections_ap);
+ unified_section_list = *m_sections_ap;
+ }
+ }
+}
+
+void
+ObjectFileJIT::Dump (Stream *s)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ s->Printf("%p: ", static_cast<void*>(this));
+ s->Indent();
+ s->PutCString("ObjectFileJIT");
+
+ ArchSpec arch;
+ if (GetArchitecture(arch))
+ *s << ", arch = " << arch.GetArchitectureName();
+
+ s->EOL();
+
+ SectionList *sections = GetSectionList();
+ if (sections)
+ sections->Dump(s, NULL, true, UINT32_MAX);
+
+ if (m_symtab_ap.get())
+ m_symtab_ap->Dump(s, NULL, eSortOrderNone);
+ }
+}
+
+bool
+ObjectFileJIT::GetUUID (lldb_private::UUID* uuid)
+{
+ // TODO: maybe get from delegate, not needed for first pass
+ return false;
+}
+
+
+uint32_t
+ObjectFileJIT::GetDependentModules (FileSpecList& files)
+{
+ // JIT modules don't have dependencies, but they could
+ // if external functions are called and we know where they are
+ files.Clear();
+ return 0;
+}
+
+lldb_private::Address
+ObjectFileJIT::GetEntryPointAddress ()
+{
+ return Address();
+}
+
+lldb_private::Address
+ObjectFileJIT::GetHeaderAddress ()
+{
+ return Address();
+}
+
+
+
+ObjectFile::Type
+ObjectFileJIT::CalculateType()
+{
+ return eTypeJIT;
+}
+
+ObjectFile::Strata
+ObjectFileJIT::CalculateStrata()
+{
+ return eStrataJIT;
+}
+
+
+bool
+ObjectFileJIT::GetArchitecture (ArchSpec &arch)
+{
+ ObjectFileJITDelegateSP delegate_sp (m_delegate_wp.lock());
+ if (delegate_sp)
+ return delegate_sp->GetArchitecture(arch);
+ return false;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ObjectFileJIT::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectFileJIT::GetPluginVersion()
+{
+ return 1;
+}
+
+
+bool
+ObjectFileJIT::SetLoadAddress (Target &target,
+ lldb::addr_t value,
+ bool value_is_offset)
+{
+ size_t num_loaded_sections = 0;
+ SectionList *section_list = GetSectionList ();
+ if (section_list)
+ {
+ const size_t num_sections = section_list->GetSize();
+ // "value" is an offset to apply to each top level segment
+ for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx)
+ {
+ // Iterate through the object file sections to find all
+ // of the sections that size on disk (to avoid __PAGEZERO)
+ // and load them
+ SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx));
+ if (section_sp &&
+ section_sp->GetFileSize() > 0 &&
+ section_sp->IsThreadSpecific() == false)
+ {
+ if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + value))
+ ++num_loaded_sections;
+ }
+ }
+ }
+ return num_loaded_sections > 0;
+}
+
+
+size_t
+ObjectFileJIT::ReadSectionData (const lldb_private::Section *section,
+ lldb::offset_t section_offset,
+ void *dst,
+ size_t dst_len) const
+{
+ lldb::offset_t file_size = section->GetFileSize();
+ if (section_offset < file_size)
+ {
+ size_t src_len = file_size - section_offset;
+ if (src_len > dst_len)
+ src_len = dst_len;
+ const uint8_t *src = ((uint8_t *)(uintptr_t)section->GetFileOffset()) + section_offset;
+
+ memcpy (dst, src, src_len);
+ return src_len;
+ }
+ return 0;
+}
+
+size_t
+ObjectFileJIT::ReadSectionData (const lldb_private::Section *section,
+ lldb_private::DataExtractor& section_data) const
+{
+ if (section->GetFileSize())
+ {
+ const void *src = (void *)(uintptr_t)section->GetFileOffset();
+
+ DataBufferSP data_sp (new lldb_private::DataBufferHeap(src, section->GetFileSize()));
+ if (data_sp)
+ {
+ section_data.SetData (data_sp, 0, data_sp->GetByteSize());
+ section_data.SetByteOrder (GetByteOrder());
+ section_data.SetAddressByteSize (GetAddressByteSize());
+ return section_data.GetByteSize();
+ }
+ }
+ section_data.Clear();
+ return 0;
+}
+
diff --git a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h
new file mode 100644
index 000000000000..47140f5bcaff
--- /dev/null
+++ b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h
@@ -0,0 +1,142 @@
+//===-- ObjectFileJIT.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_ObjectFileJIT_h_
+#define liblldb_ObjectFileJIT_h_
+
+#include "lldb/Core/Address.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+
+//----------------------------------------------------------------------
+// This class needs to be hidden as eventually belongs in a plugin that
+// will export the ObjectFile protocol
+//----------------------------------------------------------------------
+class ObjectFileJIT :
+ public lldb_private::ObjectFile
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::ObjectFile *
+ CreateInstance (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length);
+
+ static lldb_private::ObjectFile *
+ CreateMemoryInstance (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr);
+
+ static size_t
+ GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb_private::ModuleSpecList &specs);
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ ObjectFileJIT (const lldb::ModuleSP &module_sp,
+ const lldb::ObjectFileJITDelegateSP &delegate_sp);
+
+ virtual
+ ~ObjectFileJIT();
+
+ virtual bool
+ ParseHeader ();
+
+ virtual bool
+ SetLoadAddress(lldb_private::Target &target,
+ lldb::addr_t value,
+ bool value_is_offset);
+
+ virtual lldb::ByteOrder
+ GetByteOrder () const;
+
+ virtual bool
+ IsExecutable () const;
+
+ virtual uint32_t
+ GetAddressByteSize () const;
+
+ virtual lldb_private::Symtab *
+ GetSymtab();
+
+ virtual bool
+ IsStripped ();
+
+ virtual void
+ CreateSections (lldb_private::SectionList &unified_section_list);
+
+ virtual void
+ Dump (lldb_private::Stream *s);
+
+ virtual bool
+ GetArchitecture (lldb_private::ArchSpec &arch);
+
+ virtual bool
+ GetUUID (lldb_private::UUID* uuid);
+
+ virtual uint32_t
+ GetDependentModules (lldb_private::FileSpecList& files);
+
+ virtual size_t
+ ReadSectionData (const lldb_private::Section *section,
+ lldb::offset_t section_offset,
+ void *dst,
+ size_t dst_len) const;
+ virtual size_t
+ ReadSectionData (const lldb_private::Section *section,
+ lldb_private::DataExtractor& section_data) const;
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual lldb_private::Address
+ GetEntryPointAddress ();
+
+ virtual lldb_private::Address
+ GetHeaderAddress ();
+
+ virtual ObjectFile::Type
+ CalculateType();
+
+ virtual ObjectFile::Strata
+ CalculateStrata();
+protected:
+ lldb::ObjectFileJITDelegateWP m_delegate_wp;
+};
+
+#endif // liblldb_ObjectFileJIT_h_
diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
index 7eca67ac7f57..7aa940a530b4 100644
--- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
+++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
@@ -1,4 +1,4 @@
-//===-- PlatformFreeBSD.cpp ---------------------------------------*- C++ -*-===//
+//===-- PlatformFreeBSD.cpp -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -27,6 +27,7 @@
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
using namespace lldb;
using namespace lldb_private;
@@ -47,10 +48,10 @@ PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
case llvm::Triple::PC:
create = true;
break;
-
+
#if defined(__FreeBSD__) || defined(__OpenBSD__)
// Only accept "unknown" for the vendor if the host is BSD and
- // it "unknown" wasn't specified (it was just returned becasue it
+ // it "unknown" wasn't specified (it was just returned because it
// was NOT specified)
case llvm::Triple::UnknownArch:
create = !arch->TripleVendorWasSpecified();
@@ -59,7 +60,7 @@ PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
default:
break;
}
-
+
if (create)
{
switch (triple.getOS())
@@ -67,10 +68,10 @@ PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
case llvm::Triple::FreeBSD:
case llvm::Triple::KFreeBSD:
break;
-
+
#if defined(__FreeBSD__) || defined(__OpenBSD__)
// Only accept "unknown" for the OS if the host is BSD and
- // it "unknown" wasn't specified (it was just returned becasue it
+ // it "unknown" wasn't specified (it was just returned because it
// was NOT specified)
case llvm::Triple::UnknownOS:
create = arch->TripleOSWasSpecified();
@@ -122,7 +123,7 @@ PlatformFreeBSD::Initialize ()
#if defined (__FreeBSD__)
// Force a host flag to true for the default platform object.
PlatformSP default_platform_sp (new PlatformFreeBSD(true));
- default_platform_sp->SetSystemArchitecture (Host::GetArchitecture());
+ default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
Platform::SetDefaultPlatform (default_platform_sp);
#endif
PluginManager::RegisterPlugin(PlatformFreeBSD::GetPluginNameStatic(false),
@@ -186,10 +187,10 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
{
Error error;
// Nothing special to do here, just use the actual file and architecture
-
+
char exe_path[PATH_MAX];
FileSpec resolved_exe_file (exe_file);
-
+
if (IsHost())
{
// If we have "ls" as the exe_file, resolve the executable location based on
@@ -199,10 +200,10 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
exe_file.GetPath(exe_path, sizeof(exe_path));
resolved_exe_file.SetFile(exe_path, true);
}
-
+
if (!resolved_exe_file.Exists())
resolved_exe_file.ResolveExecutableLocation ();
-
+
if (resolved_exe_file.Exists())
error.Clear();
else
@@ -223,10 +224,10 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
else
{
// We may connect to a process and use the provided executable (Don't use local $PATH).
-
+
// Resolve any executable within a bundle on MacOSX
Host::ResolveExecutableInBundle (resolved_exe_file);
-
+
if (resolved_exe_file.Exists()) {
error.Clear();
}
@@ -248,7 +249,7 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
module_search_paths_ptr,
NULL,
NULL);
-
+
if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL)
{
exe_module_sp.reset();
@@ -279,18 +280,25 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
else
error.SetErrorToGenericError();
}
-
+
if (idx > 0)
arch_names.PutCString (", ");
arch_names.PutCString (platform_arch.GetArchitectureName());
}
-
+
if (error.Fail() || !exe_module_sp)
{
- error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
- exe_file.GetPath().c_str(),
- GetPluginName().GetCString(),
- arch_names.GetString().c_str());
+ if (exe_file.Readable())
+ {
+ error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
+ exe_file.GetPath().c_str(),
+ GetPluginName().GetCString(),
+ arch_names.GetString().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' is not readable", exe_file.GetPath().c_str());
+ }
}
}
}
@@ -305,15 +313,13 @@ PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite
const uint8_t *trap_opcode = NULL;
size_t trap_opcode_size = 0;
- switch (arch.GetCore())
+ switch (arch.GetMachine())
{
default:
assert(false && "Unhandled architecture in PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode()");
break;
-
- case ArchSpec::eCore_x86_32_i386:
- case ArchSpec::eCore_x86_64_x86_64:
- case ArchSpec::eCore_x86_64_x86_64h:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
{
static const uint8_t g_i386_opcode[] = { 0xCC };
trap_opcode = g_i386_opcode;
@@ -451,7 +457,7 @@ PlatformFreeBSD::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_i
{
success = Platform::GetProcessInfo (pid, process_info);
}
- else if (m_remote_platform_sp)
+ else if (m_remote_platform_sp)
{
success = m_remote_platform_sp->GetProcessInfo (pid, process_info);
}
@@ -633,19 +639,19 @@ PlatformFreeBSD::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
// From macosx;s plugin code. For FreeBSD we may want to support more archs.
if (idx == 0)
{
- arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
+ arch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
return arch.IsValid();
}
else if (idx == 1)
{
- ArchSpec platform_arch (Host::GetArchitecture (Host::eSystemDefaultArchitecture));
- ArchSpec platform_arch64 (Host::GetArchitecture (Host::eSystemDefaultArchitecture64));
+ ArchSpec platform_arch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
+ ArchSpec platform_arch64(HostInfo::GetArchitecture(HostInfo::eArchKind64));
if (platform_arch.IsExactMatch(platform_arch64))
{
// This freebsd platform supports both 32 and 64 bit. Since we already
// returned the 64 bit arch for idx == 0, return the 32 bit arch
// for idx == 1
- arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture32);
+ arch = HostInfo::GetArchitecture(HostInfo::eArchKind32);
return arch.IsValid();
}
}
diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
index 0682eacc5a43..62958a08a9e0 100644
--- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
+++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
@@ -1,4 +1,4 @@
-//===-- PlatformFreeBSD.h -----------------------------------------*- C++ -*-===//
+//===-- PlatformFreeBSD.h ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
index bb07d999c4c2..cc4c693e1b43 100644
--- a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
+++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
@@ -18,8 +18,11 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Host/File.h"
+#include "lldb/Host/FileCache.h"
#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
using namespace lldb;
using namespace lldb_private;
@@ -57,6 +60,16 @@ PlatformPOSIX::GetConnectionOptions (lldb_private::CommandInterpreter& interpret
return m_options.get();
}
+bool
+PlatformPOSIX::IsConnected () const
+{
+ if (IsHost())
+ return true;
+ else if (m_remote_platform_sp)
+ return m_remote_platform_sp->IsConnected();
+ return false;
+}
+
lldb_private::Error
PlatformPOSIX::RunShellCommand (const char *command, // Shouldn't be NULL
const char *working_dir, // Pass NULL to use the current working directory
@@ -98,7 +111,7 @@ Error
PlatformPOSIX::SetFilePermissions (const char *path, uint32_t file_permissions)
{
if (m_remote_platform_sp)
- return m_remote_platform_sp->MakeDirectory(path, file_permissions);
+ return m_remote_platform_sp->SetFilePermissions(path, file_permissions);
else
return Platform::SetFilePermissions(path ,file_permissions);
}
@@ -110,7 +123,7 @@ PlatformPOSIX::OpenFile (const FileSpec& file_spec,
Error &error)
{
if (IsHost())
- return Host::OpenFile(file_spec, flags, mode, error);
+ return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error);
else if (m_remote_platform_sp)
return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error);
else
@@ -121,7 +134,7 @@ bool
PlatformPOSIX::CloseFile (lldb::user_id_t fd, Error &error)
{
if (IsHost())
- return Host::CloseFile(fd, error);
+ return FileCache::GetInstance().CloseFile(fd, error);
else if (m_remote_platform_sp)
return m_remote_platform_sp->CloseFile(fd, error);
else
@@ -136,7 +149,7 @@ PlatformPOSIX::ReadFile (lldb::user_id_t fd,
Error &error)
{
if (IsHost())
- return Host::ReadFile(fd, offset, dst, dst_len, error);
+ return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error);
else if (m_remote_platform_sp)
return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error);
else
@@ -151,7 +164,7 @@ PlatformPOSIX::WriteFile (lldb::user_id_t fd,
Error &error)
{
if (IsHost())
- return Host::WriteFile(fd, offset, src, src_len, error);
+ return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error);
else if (m_remote_platform_sp)
return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error);
else
@@ -339,7 +352,7 @@ lldb::user_id_t
PlatformPOSIX::GetFileSize (const FileSpec& file_spec)
{
if (IsHost())
- return Host::GetFileSize(file_spec);
+ return FileSystem::GetFileSize(file_spec);
else if (m_remote_platform_sp)
return m_remote_platform_sp->GetFileSize(file_spec);
else
@@ -350,7 +363,7 @@ Error
PlatformPOSIX::CreateSymlink(const char *src, const char *dst)
{
if (IsHost())
- return Host::Symlink(src, dst);
+ return FileSystem::Symlink(src, dst);
else if (m_remote_platform_sp)
return m_remote_platform_sp->CreateSymlink(src, dst);
else
@@ -372,7 +385,7 @@ Error
PlatformPOSIX::Unlink (const char *path)
{
if (IsHost())
- return Host::Unlink (path);
+ return FileSystem::Unlink(path);
else if (m_remote_platform_sp)
return m_remote_platform_sp->Unlink(path);
else
@@ -469,10 +482,9 @@ PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path
if (permissions == 0)
permissions = lldb::eFilePermissionsFileDefault;
- user_id_t fd_dst = Host::OpenFile(destination,
- File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate,
- permissions,
- error);
+ user_id_t fd_dst = FileCache::GetInstance().OpenFile(
+ destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate, permissions,
+ error);
if (fd_dst == UINT64_MAX)
{
@@ -496,15 +508,11 @@ PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path
break;
if (n_read == 0)
break;
- if (Host::WriteFile(fd_dst,
- offset,
- buffer_sp->GetBytes(),
- n_read,
- error) != n_read)
+ if (FileCache::GetInstance().WriteFile(fd_dst, offset, buffer_sp->GetBytes(), n_read, error) != n_read)
{
if (!error.Fail())
error.SetErrorString("unable to write to destination file");
- break;
+ break;
}
offset += n_read;
}
@@ -513,7 +521,7 @@ PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path
if (fd_src != UINT64_MAX)
CloseFile(fd_src, error);
// And close the dst file descriptot.
- if (fd_dst != UINT64_MAX && !Host::CloseFile(fd_dst, error))
+ if (fd_dst != UINT64_MAX && !FileCache::GetInstance().CloseFile(fd_dst, error))
{
if (!error.Fail())
error.SetErrorString("unable to close destination file");
@@ -589,6 +597,176 @@ PlatformPOSIX::SetRemoteWorkingDirectory(const lldb_private::ConstString &path)
return Platform::SetRemoteWorkingDirectory(path);
}
+bool
+PlatformPOSIX::GetRemoteOSVersion ()
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetOSVersion (m_major_os_version,
+ m_minor_os_version,
+ m_update_os_version);
+ return false;
+}
+
+bool
+PlatformPOSIX::GetRemoteOSBuildString (std::string &s)
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetRemoteOSBuildString (s);
+ s.clear();
+ return false;
+}
+
+bool
+PlatformPOSIX::GetRemoteOSKernelDescription (std::string &s)
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetRemoteOSKernelDescription (s);
+ s.clear();
+ return false;
+}
+
+// Remote Platform subclasses need to override this function
+ArchSpec
+PlatformPOSIX::GetRemoteSystemArchitecture ()
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetRemoteSystemArchitecture ();
+ return ArchSpec();
+}
+
+const char *
+PlatformPOSIX::GetHostname ()
+{
+ if (IsHost())
+ return Platform::GetHostname();
+
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetHostname ();
+ return NULL;
+}
+
+const char *
+PlatformPOSIX::GetUserName (uint32_t uid)
+{
+ // Check the cache in Platform in case we have already looked this uid up
+ const char *user_name = Platform::GetUserName(uid);
+ if (user_name)
+ return user_name;
+
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->GetUserName(uid);
+ return NULL;
+}
+
+const char *
+PlatformPOSIX::GetGroupName (uint32_t gid)
+{
+ const char *group_name = Platform::GetGroupName(gid);
+ if (group_name)
+ return group_name;
+
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->GetGroupName(gid);
+ return NULL;
+}
+
+Error
+PlatformPOSIX::ConnectRemote (Args& args)
+{
+ Error error;
+ if (IsHost())
+ {
+ error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString());
+ }
+ else
+ {
+ if (!m_remote_platform_sp)
+ m_remote_platform_sp = Platform::Create ("remote-gdb-server", error);
+
+ if (m_remote_platform_sp && error.Success())
+ error = m_remote_platform_sp->ConnectRemote (args);
+ else
+ error.SetErrorString ("failed to create a 'remote-gdb-server' platform");
+
+ if (error.Fail())
+ m_remote_platform_sp.reset();
+ }
+
+ if (error.Success() && m_remote_platform_sp)
+ {
+ if (m_options.get())
+ {
+ OptionGroupOptions* options = m_options.get();
+ OptionGroupPlatformRSync* m_rsync_options = (OptionGroupPlatformRSync*)options->GetGroupWithOption('r');
+ OptionGroupPlatformSSH* m_ssh_options = (OptionGroupPlatformSSH*)options->GetGroupWithOption('s');
+ OptionGroupPlatformCaching* m_cache_options = (OptionGroupPlatformCaching*)options->GetGroupWithOption('c');
+
+ if (m_rsync_options->m_rsync)
+ {
+ SetSupportsRSync(true);
+ SetRSyncOpts(m_rsync_options->m_rsync_opts.c_str());
+ SetRSyncPrefix(m_rsync_options->m_rsync_prefix.c_str());
+ SetIgnoresRemoteHostname(m_rsync_options->m_ignores_remote_hostname);
+ }
+ if (m_ssh_options->m_ssh)
+ {
+ SetSupportsSSH(true);
+ SetSSHOpts(m_ssh_options->m_ssh_opts.c_str());
+ }
+ SetLocalCacheDirectory(m_cache_options->m_cache_dir.c_str());
+ }
+ }
+
+ return error;
+}
+
+Error
+PlatformPOSIX::DisconnectRemote ()
+{
+ Error error;
+
+ if (IsHost())
+ {
+ error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetPluginName().GetCString());
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ error = m_remote_platform_sp->DisconnectRemote ();
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return error;
+}
+
+lldb::ProcessSP
+PlatformPOSIX::DebugProcess (ProcessLaunchInfo &launch_info,
+ Debugger &debugger,
+ Target *target, // Can be NULL, if NULL create a new target, else use existing one
+ Listener &listener,
+ Error &error)
+{
+ ProcessSP process_sp;
+
+ if (IsHost())
+ {
+ // We are going to hand this process off to debugserver which will be in charge of setting the exit status.
+ // We still need to reap it from lldb but if we let the monitor thread also set the exit status, we set up a
+ // race between debugserver & us for who will find out about the debugged process's death.
+ launch_info.GetFlags().Set(eLaunchFlagDontSetExitStatus);
+ process_sp = Platform::DebugProcess (launch_info, debugger, target, listener, error);
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ process_sp = m_remote_platform_sp->DebugProcess (launch_info, debugger, target, listener, error);
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return process_sp;
+
+}
+
void
PlatformPOSIX::CalculateTrapHandlerSymbolNames ()
{
diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/source/Plugins/Platform/POSIX/PlatformPOSIX.h
index 130c84bdface..374e36495d88 100644
--- a/source/Plugins/Platform/POSIX/PlatformPOSIX.h
+++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.h
@@ -33,7 +33,16 @@ public:
//------------------------------------------------------------
virtual lldb_private::OptionGroupOptions*
GetConnectionOptions (lldb_private::CommandInterpreter& interpreter);
-
+
+ const char *
+ GetHostname () override;
+
+ const char *
+ GetUserName (uint32_t uid) override;
+
+ const char *
+ GetGroupName (uint32_t gid) override;
+
virtual lldb_private::Error
PutFile (const lldb_private::FileSpec& source,
const lldb_private::FileSpec& destination,
@@ -79,7 +88,22 @@ public:
virtual bool
SetRemoteWorkingDirectory(const lldb_private::ConstString &path);
-
+
+ bool
+ GetRemoteOSVersion () override;
+
+ bool
+ GetRemoteOSBuildString (std::string &s) override;
+
+ bool
+ GetRemoteOSKernelDescription (std::string &s) override;
+
+ lldb_private::ArchSpec
+ GetRemoteSystemArchitecture () override;
+
+ bool
+ IsConnected () const override;
+
virtual lldb_private::Error
RunShellCommand (const char *command, // Shouldn't be NULL
const char *working_dir, // Pass NULL to use the current working directory
@@ -103,6 +127,13 @@ public:
virtual lldb_private::Error
Unlink (const char *path);
+ lldb::ProcessSP
+ DebugProcess (lldb_private::ProcessLaunchInfo &launch_info,
+ lldb_private::Debugger &debugger,
+ lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one
+ lldb_private::Listener &listener,
+ lldb_private::Error &error) override;
+
virtual std::string
GetPlatformSpecificConnectionInformation();
@@ -114,6 +145,12 @@ public:
virtual void
CalculateTrapHandlerSymbolNames ();
+ lldb_private::Error
+ ConnectRemote (lldb_private::Args& args) override;
+
+ lldb_private::Error
+ DisconnectRemote () override;
+
protected:
std::unique_ptr<lldb_private::OptionGroupOptions> m_options;
diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
index 3832265638db..05fbc5101278 100644
--- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
+++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
@@ -12,11 +12,6 @@
#include "PlatformRemoteGDBServer.h"
#include "lldb/Host/Config.h"
-// C Includes
-#ifndef LLDB_DISABLE_POSIX
-#include <sys/sysctl.h>
-#endif
-
// C++ Includes
// Other libraries and framework includes
// Project includes
@@ -24,6 +19,7 @@
#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/PluginManager.h"
@@ -346,13 +342,18 @@ PlatformRemoteGDBServer::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &p
Error
PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
Error error;
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
-
+
+ if (log)
+ log->Printf ("PlatformRemoteGDBServer::%s() called", __FUNCTION__);
+
m_gdb_client.SetSTDIN ("/dev/null");
m_gdb_client.SetSTDOUT ("/dev/null");
m_gdb_client.SetSTDERR ("/dev/null");
m_gdb_client.SetDisableASLR (launch_info.GetFlags().Test (eLaunchFlagDisableASLR));
+ m_gdb_client.SetDetachOnError (launch_info.GetFlags().Test (eLaunchFlagDetachOnError));
const char *working_dir = launch_info.GetWorkingDirectory();
if (working_dir && working_dir[0])
@@ -377,7 +378,9 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
const char *arch_triple = arch_spec.GetTriple().str().c_str();
m_gdb_client.SendLaunchArchPacket(arch_triple);
-
+ if (log)
+ log->Printf ("PlatformRemoteGDBServer::%s() set launch architecture triple to '%s'", __FUNCTION__, arch_triple ? arch_triple : "<NULL>");
+
const uint32_t old_packet_timeout = m_gdb_client.SetPacketTimeout (5);
int arg_packet_err = m_gdb_client.SendArgumentsPacket (launch_info);
m_gdb_client.SetPacketTimeout (old_packet_timeout);
@@ -388,11 +391,23 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
{
pid = m_gdb_client.GetCurrentProcessID ();
if (pid != LLDB_INVALID_PROCESS_ID)
+ {
launch_info.SetProcessID (pid);
+ if (log)
+ log->Printf ("PlatformRemoteGDBServer::%s() pid %" PRIu64 " launched successfully", __FUNCTION__, pid);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("PlatformRemoteGDBServer::%s() launch succeeded but we didn't get a valid process id back!", __FUNCTION__);
+ // FIXME isn't this an error condition? Do we need to set an error here? Check with Greg.
+ }
}
else
{
error.SetErrorString (error_str.c_str());
+ if (log)
+ log->Printf ("PlatformRemoteGDBServer::%s() launch failed: %s", __FUNCTION__, error.AsCString ());
}
}
else
@@ -423,7 +438,7 @@ PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_i
// When remote debugging to iOS, we use a USB mux that always talks
// to localhost, so we will need the remote debugserver to accept connections
// only from localhost, no matter what our current hostname is
- port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "localhost");
+ port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "127.0.0.1");
}
else
{
@@ -511,7 +526,7 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
// When remote debugging to iOS, we use a USB mux that always talks
// to localhost, so we will need the remote debugserver to accept connections
// only from localhost, no matter what our current hostname is
- port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "localhost");
+ port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "127.0.0.1");
}
else
{
diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
index d13b9a485858..4b488444de1e 100644
--- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
+++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
@@ -22,12 +22,23 @@
#include "ProcessFreeBSD.h"
#include "ProcessPOSIXLog.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "Plugins/Process/Utility/FreeBSDSignals.h"
#include "ProcessMonitor.h"
#include "FreeBSDThread.h"
using namespace lldb;
using namespace lldb_private;
+namespace
+{
+ UnixSignalsSP&
+ GetFreeBSDSignals ()
+ {
+ static UnixSignalsSP s_freebsd_signals_sp (new FreeBSDSignals ());
+ return s_freebsd_signals_sp;
+ }
+}
+
//------------------------------------------------------------------------------
// Static functions.
@@ -113,7 +124,8 @@ ProcessFreeBSD::EnablePluginLogging(Stream *strm, Args &command)
// Constructors and destructors.
ProcessFreeBSD::ProcessFreeBSD(Target& target, Listener &listener)
- : ProcessPOSIX(target, listener)
+ : ProcessPOSIX(target, listener, GetFreeBSDSignals ()),
+ m_resume_signo(0)
{
}
@@ -132,8 +144,6 @@ ProcessFreeBSD::DoDetach(bool keep_stopped)
return error;
}
- DisableAllBreakpointSites();
-
error = m_monitor->Detach(GetID());
if (error.Success())
@@ -147,9 +157,6 @@ ProcessFreeBSD::DoResume()
{
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
- // FreeBSD's ptrace() uses 0 to indicate "no signal is to be sent."
- int resume_signal = 0;
-
SetPrivateState(eStateRunning);
Mutex::Locker lock(m_thread_list.GetMutex());
@@ -172,11 +179,11 @@ ProcessFreeBSD::DoResume()
}
if (log)
- log->Printf("process %lu resuming (%s)", GetID(), do_step ? "step" : "continue");
+ log->Printf("process %" PRIu64 " resuming (%s)", GetID(), do_step ? "step" : "continue");
if (do_step)
- m_monitor->SingleStep(GetID(), resume_signal);
+ m_monitor->SingleStep(GetID(), m_resume_signo);
else
- m_monitor->Resume(GetID(), resume_signal);
+ m_monitor->Resume(GetID(), m_resume_signo);
return Error();
}
@@ -228,6 +235,7 @@ ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_th
Error
ProcessFreeBSD::WillResume()
{
+ m_resume_signo = 0;
m_suspend_tids.clear();
m_run_tids.clear();
m_step_tids.clear();
@@ -274,4 +282,3 @@ ProcessFreeBSD::SendMessage(const ProcessMessage &message)
m_message_queue.push(message);
}
-
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
index 3d793d0c1c20..63439b155111 100644
--- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
@@ -702,7 +702,7 @@ EventMessageOperation::Execute(ProcessMonitor *monitor)
//------------------------------------------------------------------------------
/// @class KillOperation
-/// @brief Implements ProcessMonitor::BringProcessIntoLimbo.
+/// @brief Implements ProcessMonitor::Kill.
class KillOperation : public Operation
{
public:
@@ -727,7 +727,7 @@ KillOperation::Execute(ProcessMonitor *monitor)
//------------------------------------------------------------------------------
/// @class DetachOperation
-/// @brief Implements ProcessMonitor::BringProcessIntoLimbo.
+/// @brief Implements ProcessMonitor::Detach.
class DetachOperation : public Operation
{
public:
@@ -807,6 +807,7 @@ ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
const char *stdout_path,
const char *stderr_path,
const char *working_dir,
+ const lldb_private::ProcessLaunchInfo & /* launch_info */,
lldb_private::Error &error)
: m_process(static_cast<ProcessFreeBSD *>(process)),
m_operation_thread(LLDB_INVALID_HOST_THREAD),
@@ -1628,9 +1629,13 @@ ProcessMonitor::Resume(lldb::tid_t unused, uint32_t signo)
bool result;
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
- if (log)
- log->Printf ("ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s", __FUNCTION__, GetPID(),
- m_process->GetUnixSignals().GetSignalAsCString (signo));
+ if (log) {
+ const char *signame = m_process->GetUnixSignals().GetSignalAsCString (signo);
+ if (signame == nullptr)
+ signame = "<none>";
+ log->Printf("ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s",
+ __FUNCTION__, GetPID(), signame);
+ }
ResumeOperation op(signo, result);
DoOperation(&op);
if (log)
@@ -1648,7 +1653,7 @@ ProcessMonitor::SingleStep(lldb::tid_t unused, uint32_t signo)
}
bool
-ProcessMonitor::BringProcessIntoLimbo()
+ProcessMonitor::Kill()
{
bool result;
KillOperation op(result);
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h
index 4c8198fb2e4c..314743b00754 100644
--- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h
@@ -55,6 +55,7 @@ public:
const char *stdout_path,
const char *stderr_path,
const char *working_dir,
+ const lldb_private::ProcessLaunchInfo &launch_info,
lldb_private::Error &error);
ProcessMonitor(ProcessPOSIX *process,
@@ -194,11 +195,9 @@ public:
bool
SingleStep(lldb::tid_t unused, uint32_t signo);
- /// Sends the inferior process a PTRACE_KILL signal. The inferior will
- /// still exists and can be interrogated. Once resumed it will exit as
- /// though it received a SIGKILL.
+ /// Terminate the traced process.
bool
- BringProcessIntoLimbo();
+ Kill();
lldb_private::Error
Detach(lldb::tid_t tid);
diff --git a/source/Plugins/Process/POSIX/POSIXThread.cpp b/source/Plugins/Process/POSIX/POSIXThread.cpp
index cc759eaad96d..d48f8f9dd307 100644
--- a/source/Plugins/Process/POSIX/POSIXThread.cpp
+++ b/source/Plugins/Process/POSIX/POSIXThread.cpp
@@ -20,6 +20,7 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/State.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
@@ -29,8 +30,10 @@
#include "ProcessPOSIX.h"
#include "ProcessPOSIXLog.h"
#include "ProcessMonitor.h"
+#include "RegisterContextPOSIXProcessMonitor_arm64.h"
#include "RegisterContextPOSIXProcessMonitor_mips64.h"
#include "RegisterContextPOSIXProcessMonitor_x86.h"
+#include "RegisterContextLinux_arm64.h"
#include "RegisterContextLinux_i386.h"
#include "RegisterContextLinux_x86_64.h"
#include "RegisterContextFreeBSD_i386.h"
@@ -110,7 +113,7 @@ POSIXThread::RefreshStateAfterStop()
GetRegisterContext()->InvalidateIfNeeded (force);
}
// FIXME: This should probably happen somewhere else.
- SetResumeState(eStateRunning);
+ SetResumeState(eStateRunning, true);
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
if (log)
log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to running", __FUNCTION__, GetID());
@@ -156,58 +159,82 @@ POSIXThread::GetRegisterContext()
RegisterInfoInterface *reg_interface = NULL;
const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture();
- switch (target_arch.GetCore())
+ switch (target_arch.GetTriple().getOS())
{
- case ArchSpec::eCore_mips64:
- {
- switch (target_arch.GetTriple().getOS())
+ case llvm::Triple::FreeBSD:
+ switch (target_arch.GetMachine())
{
- case llvm::Triple::FreeBSD:
+ case llvm::Triple::mips64:
reg_interface = new RegisterContextFreeBSD_mips64(target_arch);
break;
+ case llvm::Triple::x86:
+ reg_interface = new RegisterContextFreeBSD_i386(target_arch);
+ break;
+ case llvm::Triple::x86_64:
+ reg_interface = new RegisterContextFreeBSD_x86_64(target_arch);
+ break;
default:
- assert(false && "OS not supported");
break;
}
-
- if (reg_interface)
- {
- RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface);
- m_posix_thread = reg_ctx;
- m_reg_context_sp.reset(reg_ctx);
- }
break;
- }
- case ArchSpec::eCore_x86_32_i386:
- case ArchSpec::eCore_x86_32_i486:
- case ArchSpec::eCore_x86_32_i486sx:
- case ArchSpec::eCore_x86_64_x86_64:
- {
- switch (target_arch.GetTriple().getOS())
+ case llvm::Triple::Linux:
+ switch (target_arch.GetMachine())
{
- case llvm::Triple::FreeBSD:
- reg_interface = new RegisterContextFreeBSD_x86_64(target_arch);
+ case llvm::Triple::aarch64:
+ assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host");
+ reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_arm64(target_arch));
break;
- case llvm::Triple::Linux:
- reg_interface = new RegisterContextLinux_x86_64(target_arch);
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (HostInfo::GetArchitecture().GetAddressByteSize() == 4)
+ {
+ // 32-bit hosts run with a RegisterContextLinux_i386 context.
+ reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_i386(target_arch));
+ }
+ else
+ {
+ assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
+ "Register setting path assumes this is a 64-bit host");
+ // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context.
+ reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_x86_64(target_arch));
+ }
break;
default:
- assert(false && "OS not supported");
break;
}
- if (reg_interface)
+ default:
+ break;
+ }
+
+ assert(reg_interface && "OS or CPU not supported!");
+
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ {
+ RegisterContextPOSIXProcessMonitor_arm64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm64(*this, 0, reg_interface);
+ m_posix_thread = reg_ctx;
+ m_reg_context_sp.reset(reg_ctx);
+ break;
+ }
+ case llvm::Triple::mips64:
+ {
+ RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface);
+ m_posix_thread = reg_ctx;
+ m_reg_context_sp.reset(reg_ctx);
+ break;
+ }
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
{
RegisterContextPOSIXProcessMonitor_x86_64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_x86_64(*this, 0, reg_interface);
m_posix_thread = reg_ctx;
m_reg_context_sp.reset(reg_ctx);
+ break;
}
- break;
- }
-
default:
- assert(false && "CPU type not supported!");
break;
}
}
@@ -546,18 +573,14 @@ void
POSIXThread::SignalNotify(const ProcessMessage &message)
{
int signo = message.GetSignal();
-
SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
- SetResumeSignal(signo);
}
void
POSIXThread::SignalDeliveredNotify(const ProcessMessage &message)
{
int signo = message.GetSignal();
-
SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
- SetResumeSignal(signo);
}
void
@@ -576,7 +599,6 @@ POSIXThread::CrashNotify(const ProcessMessage &message)
SetStopInfo (lldb::StopInfoSP(new POSIXCrashStopInfo(*this, signo,
message.GetCrashReason(),
message.GetFaultAddress())));
- SetResumeSignal(signo);
}
void
@@ -589,19 +611,18 @@ unsigned
POSIXThread::GetRegisterIndexFromOffset(unsigned offset)
{
unsigned reg = LLDB_INVALID_REGNUM;
- ArchSpec arch = Host::GetArchitecture();
+ ArchSpec arch = HostInfo::GetArchitecture();
- switch (arch.GetCore())
+ switch (arch.GetMachine())
{
default:
llvm_unreachable("CPU type not supported!");
break;
- case ArchSpec::eCore_mips64:
- case ArchSpec::eCore_x86_32_i386:
- case ArchSpec::eCore_x86_32_i486:
- case ArchSpec::eCore_x86_32_i486sx:
- case ArchSpec::eCore_x86_64_x86_64:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::mips64:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
{
POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol();
reg = reg_ctx->GetRegisterIndexFromOffset(offset);
@@ -621,19 +642,18 @@ const char *
POSIXThread::GetRegisterName(unsigned reg)
{
const char * name = nullptr;
- ArchSpec arch = Host::GetArchitecture();
+ ArchSpec arch = HostInfo::GetArchitecture();
- switch (arch.GetCore())
+ switch (arch.GetMachine())
{
default:
assert(false && "CPU type not supported!");
break;
- case ArchSpec::eCore_mips64:
- case ArchSpec::eCore_x86_32_i386:
- case ArchSpec::eCore_x86_32_i486:
- case ArchSpec::eCore_x86_32_i486sx:
- case ArchSpec::eCore_x86_64_x86_64:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::mips64:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
name = GetRegisterContext()->GetRegisterName(reg);
break;
}
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
index 62394623c59d..f340631c7d07 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -70,8 +70,8 @@ ProcessPOSIX::Initialize()
//------------------------------------------------------------------------------
// Constructors and destructors.
-ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener)
- : Process(target, listener),
+ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener, UnixSignalsSP &unix_signals_sp)
+ : Process(target, listener, unix_signals_sp),
m_byte_order(lldb::endian::InlHostByteOrder()),
m_monitor(NULL),
m_module(NULL),
@@ -176,23 +176,23 @@ ProcessPOSIX::WillLaunch(Module* module)
}
const char *
-ProcessPOSIX::GetFilePath(
- const lldb_private::ProcessLaunchInfo::FileAction *file_action,
- const char *default_path)
+ProcessPOSIX::GetFilePath(const lldb_private::FileAction *file_action, const char *default_path)
{
const char *pts_name = "/dev/pts/";
const char *path = NULL;
if (file_action)
{
- if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ if (file_action->GetAction() == FileAction::eFileActionOpen)
+ {
path = file_action->GetPath();
// By default the stdio paths passed in will be pseudo-terminal
// (/dev/pts). If so, convert to using a different default path
// instead to redirect I/O to the debugger console. This should
// also handle user overrides to /dev/null or a different file.
- if (::strncmp(path, pts_name, ::strlen(pts_name)) == 0)
+ if (!path || ::strncmp(path, pts_name, ::strlen(pts_name)) == 0)
path = default_path;
+ }
}
return path;
@@ -217,7 +217,7 @@ ProcessPOSIX::DoLaunch (Module *module,
SetPrivateState(eStateLaunching);
- const lldb_private::ProcessLaunchInfo::FileAction *file_action;
+ const lldb_private::FileAction *file_action;
// Default of NULL will mean to use existing open file descriptors
const char *stdin_path = NULL;
@@ -241,6 +241,7 @@ ProcessPOSIX::DoLaunch (Module *module,
stdout_path,
stderr_path,
working_dir,
+ launch_info,
error);
m_module = module;
@@ -335,11 +336,9 @@ ProcessPOSIX::DoDestroy()
if (!HasExited())
{
- // Drive the exit event to completion (do not keep the inferior in
- // limbo).
+ assert(m_monitor);
m_exit_now = true;
-
- if ((m_monitor == NULL || kill(m_monitor->GetPID(), SIGKILL)) && error.Success())
+ if (!m_monitor->Kill())
{
error.SetErrorToErrno();
return error;
@@ -379,6 +378,8 @@ ProcessPOSIX::DoDidExec()
void
ProcessPOSIX::SendMessage(const ProcessMessage &message)
{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
Mutex::Locker lock(m_message_mutex);
Mutex::Locker thread_lock(m_thread_list.GetMutex());
@@ -420,8 +421,14 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message)
break;
case ProcessMessage::eExitMessage:
- assert(thread);
- thread->SetState(eStateExited);
+ if (thread != nullptr)
+ thread->SetState(eStateExited);
+ else
+ {
+ if (log)
+ log->Warning ("ProcessPOSIX::%s eExitMessage for TID %" PRIu64 " failed to find a thread to mark as eStateExited, ignoring", __FUNCTION__, message.GetTID ());
+ }
+
// FIXME: I'm not sure we need to do this.
if (message.GetTID() == GetID())
{
@@ -635,20 +642,26 @@ ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr)
size_t
ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site)
{
+ static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xD4 };
static const uint8_t g_i386_opcode[] = { 0xCC };
ArchSpec arch = GetTarget().GetArchitecture();
const uint8_t *opcode = NULL;
size_t opcode_size = 0;
- switch (arch.GetCore())
+ switch (arch.GetMachine())
{
default:
assert(false && "CPU type not supported!");
break;
- case ArchSpec::eCore_x86_32_i386:
- case ArchSpec::eCore_x86_64_x86_64:
+ case llvm::Triple::aarch64:
+ opcode = g_aarch64_opcode;
+ opcode_size = sizeof(g_aarch64_opcode);
+ break;
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
opcode = g_i386_opcode;
opcode_size = sizeof(g_i386_opcode);
break;
@@ -865,12 +878,6 @@ ProcessPOSIX::PutSTDIN(const char *buf, size_t len, Error &error)
return status;
}
-UnixSignals &
-ProcessPOSIX::GetUnixSignals()
-{
- return m_signals;
-}
-
//------------------------------------------------------------------------------
// Utility functions.
@@ -926,3 +933,16 @@ ProcessPOSIX::IsAThreadRunning()
}
return is_running;
}
+
+const DataBufferSP
+ProcessPOSIX::GetAuxvData ()
+{
+ // If we're the local platform, we can ask the host for auxv data.
+ PlatformSP platform_sp = m_target.GetPlatform ();
+ if (platform_sp && platform_sp->IsHost ())
+ return lldb_private::Host::GetAuxvData(this);
+
+ // Somewhat unexpected - the process is not running locally or we don't have a platform.
+ assert (false && "no platform or not the host - how did we get here with ProcessPOSIX?");
+ return DataBufferSP ();
+}
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/POSIX/ProcessPOSIX.h
index 7f705d33fe68..033accf17f29 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIX.h
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.h
@@ -18,7 +18,6 @@
// Other libraries and framework includes
#include "lldb/Target/Process.h"
-#include "lldb/Target/UnixSignals.h"
#include "ProcessMessage.h"
class ProcessMonitor;
@@ -33,7 +32,8 @@ public:
// Constructors and destructors
//------------------------------------------------------------------
ProcessPOSIX(lldb_private::Target& target,
- lldb_private::Listener &listener);
+ lldb_private::Listener &listener,
+ lldb_private::UnixSignalsSP &unix_signals_sp);
virtual
~ProcessPOSIX();
@@ -141,6 +141,9 @@ public:
virtual size_t
PutSTDIN(const char *buf, size_t len, lldb_private::Error &error);
+ const lldb::DataBufferSP
+ GetAuxvData () override;
+
//--------------------------------------------------------------------------
// ProcessPOSIX internal API.
@@ -151,12 +154,7 @@ public:
ProcessMonitor &
GetMonitor() { assert(m_monitor); return *m_monitor; }
- lldb_private::UnixSignals &
- GetUnixSignals();
-
- const char *
- GetFilePath(const lldb_private::ProcessLaunchInfo::FileAction *file_action,
- const char *default_path);
+ const char *GetFilePath(const lldb_private::FileAction *file_action, const char *default_path);
/// Stops all threads in the process.
/// The \p stop_tid parameter indicates the thread which initiated the stop.
@@ -164,7 +162,7 @@ public:
StopAllThreads(lldb::tid_t stop_tid);
/// Adds the thread to the list of threads for which we have received the initial stopping signal.
- /// The \p stop_tid paramter indicates the thread which the stop happened for.
+ /// The \p stop_tid parameter indicates the thread which the stop happened for.
bool
AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid);
@@ -191,9 +189,6 @@ protected:
/// Drive any exit events to completion.
bool m_exit_now;
- /// OS-specific signal set.
- lldb_private::UnixSignals m_signals;
-
/// Returns true if the process has exited.
bool HasExited();
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp
new file mode 100644
index 000000000000..9109cdb000ae
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp
@@ -0,0 +1,318 @@
+//===-- RegisterContextPOSIXProcessMonitor_arm64.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/Target/Thread.h"
+#include "lldb/Core/RegisterValue.h"
+
+#include "RegisterContextPOSIX_arm64.h"
+#include "ProcessPOSIX.h"
+#include "RegisterContextPOSIXProcessMonitor_arm64.h"
+#include "ProcessMonitor.h"
+
+#define REG_CONTEXT_SIZE (GetGPRSize())
+
+RegisterContextPOSIXProcessMonitor_arm64::RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info)
+ : RegisterContextPOSIX_arm64(thread, concrete_frame_idx, register_info)
+{
+}
+
+ProcessMonitor &
+RegisterContextPOSIXProcessMonitor_arm64::GetMonitor()
+{
+ lldb::ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ReadGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ReadFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::WriteGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::WriteFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const unsigned reg,
+ lldb_private::RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ GetRegisterSize(reg),
+ value);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const unsigned reg,
+ const lldb_private::RegisterValue &value)
+{
+ unsigned reg_to_write = reg;
+ lldb_private::RegisterValue value_to_write = value;
+
+ // Check if this is a subregister of a full register.
+ const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
+ {
+ lldb_private::RegisterValue full_value;
+ uint32_t full_reg = reg_info->invalidate_regs[0];
+ const lldb_private::RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
+
+ // Read the full register.
+ if (ReadRegister(full_reg_info, full_value))
+ {
+ lldb_private::Error error;
+ lldb::ByteOrder byte_order = GetByteOrder();
+ uint8_t dst[lldb_private::RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the full register.
+ const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
+ dst,
+ sizeof(dst),
+ byte_order,
+ error);
+ if (error.Success() && dest_size)
+ {
+ uint8_t src[lldb_private::RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the source data.
+ const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
+ if (error.Success() && src_size && (src_size < dest_size))
+ {
+ // Copy the src bytes to the destination.
+ ::memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
+ // Set this full register as the value to write.
+ value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
+ value_to_write.SetType(full_reg_info);
+ reg_to_write = full_reg;
+ }
+ }
+ }
+ }
+
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg_to_write),
+ GetRegisterName(reg_to_write),
+ value_to_write);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+ if (IsFPR(reg))
+ {
+ if (!ReadFPR())
+ return false;
+ }
+ else
+ {
+ uint32_t full_reg = reg;
+ bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
+
+ if (is_subreg)
+ {
+ // Read the full aligned 64-bit register.
+ full_reg = reg_info->invalidate_regs[0];
+ }
+ return ReadRegister(full_reg, value);
+ }
+
+ // Get pointer to m_fpr variable and set the data from it.
+ assert (reg_info->byte_offset < sizeof m_fpr);
+ uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
+ switch (reg_info->byte_size)
+ {
+ case 2:
+ value.SetUInt16(*(uint16_t *)src);
+ return true;
+ case 4:
+ value.SetUInt32(*(uint32_t *)src);
+ return true;
+ case 8:
+ value.SetUInt64(*(uint64_t *)src);
+ return true;
+ default:
+ assert(false && "Unhandled data size.");
+ return false;
+ }
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+ if (IsGPR(reg))
+ return WriteRegister(reg, value);
+
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ bool success = false;
+ data_sp.reset (new lldb_private::DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp && ReadGPR () && ReadFPR ())
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ success = dst != 0;
+
+ if (success)
+ {
+ ::memcpy (dst, &m_gpr_arm64, GetGPRSize());
+ dst += GetGPRSize();
+ ::memcpy (dst, &m_fpr, sizeof m_fpr);
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ bool success = false;
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ uint8_t *src = data_sp->GetBytes();
+ if (src)
+ {
+ ::memcpy (&m_gpr_arm64, src, GetGPRSize());
+ if (WriteGPR()) {
+ src += GetGPRSize();
+ ::memcpy (&m_fpr, src, sizeof m_fpr);
+ success = WriteFPR();
+ }
+ }
+ }
+ return success;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
+ bool read, bool write)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ uint32_t hw_index;
+
+ for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
+ {
+ if (IsWatchpointVacant(hw_index))
+ return SetHardwareWatchpointWithIndex(addr, size,
+ read, write,
+ hw_index);
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::HardwareSingleStep(bool enable)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint()
+{
+ // PC points one byte past the int3 responsible for the breakpoint.
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ SetPC(pc - 1);
+ return true;
+}
+
+unsigned
+RegisterContextPOSIXProcessMonitor_arm64::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < k_num_registers_arm64; reg++)
+ {
+ if (GetRegisterInfo()[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < k_num_registers_arm64 && "Invalid register offset.");
+ return reg;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointHit(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ClearWatchpointHits()
+{
+ return false;
+}
+
+lldb::addr_t
+RegisterContextPOSIXProcessMonitor_arm64::GetWatchpointAddress(uint32_t hw_index)
+{
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointVacant(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_arm64::NumSupportedHardwareWatchpoints()
+{
+ return 0;
+}
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h
new file mode 100644
index 000000000000..eb24d4852ab8
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h
@@ -0,0 +1,95 @@
+//===-- RegisterContextPOSIXProcessMonitor_arm64.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_RegisterContextPOSIXProcessMonitor_arm64_H_
+#define liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
+
+class RegisterContextPOSIXProcessMonitor_arm64:
+ public RegisterContextPOSIX_arm64,
+ public POSIXBreakpointProtocol
+{
+public:
+ RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+protected:
+ bool
+ ReadGPR();
+
+ bool
+ ReadFPR();
+
+ bool
+ WriteGPR();
+
+ bool
+ WriteFPR();
+
+ // lldb_private::RegisterContext
+ bool
+ ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ uint32_t
+ SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write);
+
+ bool
+ ClearHardwareWatchpoint(uint32_t hw_index);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ // POSIXBreakpointProtocol
+ bool
+ UpdateAfterBreakpoint();
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ bool
+ IsWatchpointHit(uint32_t hw_index);
+
+ bool
+ ClearWatchpointHits();
+
+ lldb::addr_t
+ GetWatchpointAddress(uint32_t hw_index);
+
+ bool
+ IsWatchpointVacant(uint32_t hw_index);
+
+ bool
+ SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index);
+
+ uint32_t
+ NumSupportedHardwareWatchpoints();
+
+private:
+ ProcessMonitor &
+ GetMonitor();
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp
index f70d00e98a3e..9bfe236de139 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp
@@ -22,7 +22,7 @@ using namespace lldb;
RegisterContextPOSIXProcessMonitor_mips64::RegisterContextPOSIXProcessMonitor_mips64(Thread &thread,
uint32_t concrete_frame_idx,
- RegisterInfoInterface *register_info)
+ lldb_private::RegisterInfoInterface *register_info)
: RegisterContextPOSIX_mips64(thread, concrete_frame_idx, register_info)
{
}
@@ -196,7 +196,6 @@ RegisterContextPOSIXProcessMonitor_mips64::ReadAllRegisterValues(DataBufferSP &d
if (success)
{
::memcpy (dst, &m_gpr_mips64, GetGPRSize());
- dst += GetGPRSize();
}
}
return success;
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h
index 8f545eef0d5e..79e4468b1adf 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h
@@ -10,7 +10,7 @@
#ifndef liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_
#define liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_
-#include "Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
class RegisterContextPOSIXProcessMonitor_mips64:
public RegisterContextPOSIX_mips64,
@@ -19,7 +19,7 @@ class RegisterContextPOSIXProcessMonitor_mips64:
public:
RegisterContextPOSIXProcessMonitor_mips64(lldb_private::Thread &thread,
uint32_t concrete_frame_idx,
- RegisterInfoInterface *register_info);
+ lldb_private::RegisterInfoInterface *register_info);
protected:
bool
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp
index c446bbfa7dce..e534f3b4f9d0 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp
@@ -53,7 +53,7 @@ size_and_rw_bits(size_t size, bool read, bool write)
RegisterContextPOSIXProcessMonitor_x86_64::RegisterContextPOSIXProcessMonitor_x86_64(Thread &thread,
uint32_t concrete_frame_idx,
- RegisterInfoInterface *register_info)
+ lldb_private::RegisterInfoInterface *register_info)
: RegisterContextPOSIX_x86(thread, concrete_frame_idx, register_info)
{
}
@@ -347,12 +347,12 @@ RegisterContextPOSIXProcessMonitor_x86_64::ReadAllRegisterValues(DataBufferSP &d
if (success)
{
- ::memcpy (dst, &m_gpr_x86_64, GetGPRSize());
- dst += GetGPRSize();
+ ::memcpy (dst, &m_gpr_x86_64, GetGPRSize());
+ dst += GetGPRSize();
+ if (GetFPRType() == eFXSAVE)
+ ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
}
- if (GetFPRType() == eFXSAVE)
- ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
-
+
if (GetFPRType() == eXSAVE)
{
ByteOrder byte_order = GetByteOrder();
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h
index 2b64fa8003a2..2afb195c4c36 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h
@@ -10,7 +10,7 @@
#ifndef liblldb_RegisterContextPOSIXProcessMonitor_x86_H_
#define liblldb_RegisterContextPOSIXProcessMonitor_x86_H_
-#include "Plugins/Process/POSIX/RegisterContextPOSIX_x86.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h"
class RegisterContextPOSIXProcessMonitor_x86_64:
public RegisterContextPOSIX_x86,
@@ -19,7 +19,7 @@ class RegisterContextPOSIXProcessMonitor_x86_64:
public:
RegisterContextPOSIXProcessMonitor_x86_64(lldb_private::Thread &thread,
uint32_t concrete_frame_idx,
- RegisterInfoInterface *register_info);
+ lldb_private::RegisterInfoInterface *register_info);
protected:
bool
diff --git a/source/Plugins/Process/Utility/ARMDefines.h b/source/Plugins/Process/Utility/ARMDefines.h
index 4b1f06a2f9cd..2c8ad3586af1 100644
--- a/source/Plugins/Process/Utility/ARMDefines.h
+++ b/source/Plugins/Process/Utility/ARMDefines.h
@@ -10,7 +10,7 @@
#ifndef lldb_ARMDefines_h_
#define lldb_ARMDefines_h_
-// Common defintions for the ARM/Thumb Instruction Set Architecture.
+// Common definitions for the ARM/Thumb Instruction Set Architecture.
namespace lldb_private {
diff --git a/source/Plugins/Process/Utility/ARMUtils.h b/source/Plugins/Process/Utility/ARMUtils.h
index 76d64e15a53e..b6ba3fea6928 100644
--- a/source/Plugins/Process/Utility/ARMUtils.h
+++ b/source/Plugins/Process/Utility/ARMUtils.h
@@ -316,7 +316,7 @@ static inline uint32_t ARMExpandImm(uint32_t opcode)
// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
{
- uint32_t imm32; // the expaned result
+ uint32_t imm32; // the expanded result
const uint32_t i = bit(opcode, 26);
const uint32_t imm3 = bits(opcode, 14, 12);
const uint32_t abcdefgh = bits(opcode, 7, 0);
diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
index dc90b7ae02c3..3507ccf92065 100644
--- a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
+++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
@@ -115,7 +115,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
RegisterInfo reg_info;
std::vector<uint32_t> value_regs;
std::vector<uint32_t> invalidate_regs;
- bzero (&reg_info, sizeof(reg_info));
+ memset(&reg_info, 0, sizeof(reg_info));
reg_info.name = ConstString (reg_info_dict.GetItemForKeyAsString(name_pystr)).GetCString();
if (reg_info.name == NULL)
@@ -323,7 +323,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
reg_info.encoding = (Encoding)reg_info_dict.GetItemForKeyAsInteger (encoding_pystr, eEncodingUint);
const int64_t set = reg_info_dict.GetItemForKeyAsInteger(set_pystr, -1);
- if (set >= m_sets.size())
+ if (static_cast<size_t>(set) >= m_sets.size())
{
Clear();
return 0;
@@ -379,7 +379,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
if (invalidate_reg_num)
{
const int64_t r = invalidate_reg_num.GetInteger();
- if (r != UINT64_MAX)
+ if (r != static_cast<int64_t>(UINT64_MAX))
m_invalidate_regs_map[i].push_back(r);
else
printf("error: 'invalidate-regs' list value wasn't a valid integer\n");
@@ -632,10 +632,11 @@ DynamicRegisterInfo::Dump () const
{
StreamFile s(stdout, false);
const size_t num_regs = m_regs.size();
- s.Printf("%p: DynamicRegisterInfo contains %zu registers:\n", this, num_regs);
+ s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " registers:\n",
+ static_cast<const void*>(this), static_cast<uint64_t>(num_regs));
for (size_t i=0; i<num_regs; ++i)
{
- s.Printf("[%3zu] name = %-10s", i, m_regs[i].name);
+ s.Printf("[%3" PRIu64 "] name = %-10s", (uint64_t)i, m_regs[i].name);
s.Printf(", size = %2u, offset = %4u, encoding = %u, format = %-10s",
m_regs[i].byte_size,
m_regs[i].byte_offset,
@@ -671,12 +672,13 @@ DynamicRegisterInfo::Dump () const
}
s.EOL();
}
-
+
const size_t num_sets = m_sets.size();
- s.Printf("%p: DynamicRegisterInfo contains %zu register sets:\n", this, num_sets);
+ s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " register sets:\n",
+ static_cast<const void*>(this), static_cast<uint64_t>(num_sets));
for (size_t i=0; i<num_sets; ++i)
{
- s.Printf("set[%zu] name = %s, regs = [", i, m_sets[i].name);
+ s.Printf("set[%" PRIu64 "] name = %s, regs = [", (uint64_t)i, m_sets[i].name);
for (size_t idx=0; idx<m_sets[i].num_registers; ++idx)
{
s.Printf("%s ", m_regs[m_sets[i].registers[idx]].name);
diff --git a/source/Plugins/Process/Utility/FreeBSDSignals.cpp b/source/Plugins/Process/Utility/FreeBSDSignals.cpp
new file mode 100644
index 000000000000..b7c52aeb6d13
--- /dev/null
+++ b/source/Plugins/Process/Utility/FreeBSDSignals.cpp
@@ -0,0 +1,31 @@
+//===-- FreeBSDSignals.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "FreeBSDSignals.h"
+
+FreeBSDSignals::FreeBSDSignals()
+ : UnixSignals()
+{
+ Reset();
+}
+
+void
+FreeBSDSignals::Reset()
+{
+ UnixSignals::Reset();
+
+ // SIGNO NAME SHORT NAME SUPPRESS STOP NOTIFY DESCRIPTION
+ // ====== ============ ========== ======== ====== ====== ===================================================
+ AddSignal (32, "SIGTHR", "THR", false, true , true , "thread interrupt");
+ AddSignal (33, "SIGLIBRT", "LIBRT", false, true , true , "reserved by real-time library");
+}
diff --git a/source/Plugins/Process/Utility/FreeBSDSignals.h b/source/Plugins/Process/Utility/FreeBSDSignals.h
new file mode 100644
index 000000000000..1e14ccb9fc4d
--- /dev/null
+++ b/source/Plugins/Process/Utility/FreeBSDSignals.h
@@ -0,0 +1,28 @@
+//===-- FreeBSDSignals.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_FreeBSDSignals_H_
+#define liblldb_FreeBSDSignals_H_
+
+// Project includes
+#include "lldb/Target/UnixSignals.h"
+
+/// FreeBSD specific set of Unix signals.
+class FreeBSDSignals
+ : public lldb_private::UnixSignals
+{
+public:
+ FreeBSDSignals();
+
+private:
+ void
+ Reset();
+};
+
+#endif // liblldb_FreeBSDSignals_H_
diff --git a/source/Plugins/Process/Utility/HistoryThread.cpp b/source/Plugins/Process/Utility/HistoryThread.cpp
index d045bc7e10d7..590bb0162c8a 100644
--- a/source/Plugins/Process/Utility/HistoryThread.cpp
+++ b/source/Plugins/Process/Utility/HistoryThread.cpp
@@ -20,12 +20,14 @@
using namespace lldb;
using namespace lldb_private;
+// Constructor
+
HistoryThread::HistoryThread (lldb_private::Process &process,
lldb::tid_t tid,
std::vector<lldb::addr_t> pcs,
uint32_t stop_id,
bool stop_id_is_valid) :
- Thread (process, tid),
+ Thread (process, tid, true),
m_framelist_mutex(),
m_framelist(),
m_pcs (pcs),
@@ -40,14 +42,18 @@ HistoryThread::HistoryThread (lldb_private::Process &process,
m_unwinder_ap.reset (new HistoryUnwind (*this, pcs, stop_id, stop_id_is_valid));
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p HistoryThread::HistoryThread", this);
+ log->Printf ("%p HistoryThread::HistoryThread",
+ static_cast<void*>(this));
}
+// Destructor
+
HistoryThread::~HistoryThread ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p HistoryThread::~HistoryThread (tid=0x%" PRIx64 ")", this, GetID());
+ log->Printf ("%p HistoryThread::~HistoryThread (tid=0x%" PRIx64 ")",
+ static_cast<void*>(this), GetID());
DestroyThread();
}
@@ -72,7 +78,7 @@ HistoryThread::CreateRegisterContextForFrame (StackFrame *frame)
lldb::StackFrameListSP
HistoryThread::GetStackFrameList ()
{
- Mutex::Locker (m_framelist_mutex);
+ Mutex::Locker (m_framelist_mutex); // FIXME do not throw away the lock after we acquire it..
if (m_framelist.get() == NULL)
{
m_framelist.reset (new StackFrameList (*this, StackFrameListSP(), true));
diff --git a/source/Plugins/Process/Utility/HistoryUnwind.cpp b/source/Plugins/Process/Utility/HistoryUnwind.cpp
index 86665fd17b13..f809ebedcfc8 100644
--- a/source/Plugins/Process/Utility/HistoryUnwind.cpp
+++ b/source/Plugins/Process/Utility/HistoryUnwind.cpp
@@ -20,6 +20,8 @@
using namespace lldb;
using namespace lldb_private;
+// Constructor
+
HistoryUnwind::HistoryUnwind (Thread &thread,
std::vector<lldb::addr_t> pcs,
uint32_t stop_id,
@@ -31,6 +33,8 @@ HistoryUnwind::HistoryUnwind (Thread &thread,
{
}
+// Destructor
+
HistoryUnwind::~HistoryUnwind ()
{
}
@@ -62,7 +66,7 @@ HistoryUnwind::DoCreateRegisterContextForFrame (StackFrame *frame)
bool
HistoryUnwind::DoGetFrameInfoAtIndex (uint32_t frame_idx, lldb::addr_t& cfa, lldb::addr_t& pc)
{
- Mutex::Locker (m_unwind_mutex);
+ Mutex::Locker (m_unwind_mutex); // FIXME do not throw away the lock after we acquire it..
if (frame_idx < m_pcs.size())
{
cfa = frame_idx;
diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index 1d5d19fad25f..4a94457466be 100644
--- a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -117,11 +117,11 @@ lldb_private::InferiorCallMmap (Process *process,
{
ExecutionContext exe_ctx;
frame->CalculateExecutionContext (exe_ctx);
- ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ ExpressionResults result = process->RunThreadPlan (exe_ctx,
call_plan_sp,
options,
error_strm);
- if (result == eExecutionCompleted)
+ if (result == eExpressionCompleted)
{
allocated_addr = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
@@ -202,11 +202,11 @@ lldb_private::InferiorCallMunmap (Process *process,
{
ExecutionContext exe_ctx;
frame->CalculateExecutionContext (exe_ctx);
- ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ ExpressionResults result = process->RunThreadPlan (exe_ctx,
call_plan_sp,
options,
error_strm);
- if (result == eExecutionCompleted)
+ if (result == eExpressionCompleted)
{
return true;
}
@@ -260,11 +260,11 @@ lldb_private::InferiorCall (Process *process,
{
ExecutionContext exe_ctx;
frame->CalculateExecutionContext (exe_ctx);
- ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ ExpressionResults result = process->RunThreadPlan (exe_ctx,
call_plan_sp,
options,
error_strm);
- if (result == eExecutionCompleted)
+ if (result == eExpressionCompleted)
{
returned_func = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
diff --git a/source/Plugins/Process/Utility/InstructionUtils.h b/source/Plugins/Process/Utility/InstructionUtils.h
index 4bb644e6efe6..813990095c49 100644
--- a/source/Plugins/Process/Utility/InstructionUtils.h
+++ b/source/Plugins/Process/Utility/InstructionUtils.h
@@ -83,6 +83,8 @@ Rotl32 (uint32_t bits, uint32_t amt)
static inline uint64_t
MaskUpToBit (const uint64_t bit)
{
+ if (bit >= 63)
+ return -1ll;
return (1ull << (bit + 1ull)) - 1ull;
}
diff --git a/source/Plugins/Process/Utility/LinuxSignals.cpp b/source/Plugins/Process/Utility/LinuxSignals.cpp
new file mode 100644
index 000000000000..fb49df681cae
--- /dev/null
+++ b/source/Plugins/Process/Utility/LinuxSignals.cpp
@@ -0,0 +1,62 @@
+//===-- LinuxSignals.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "LinuxSignals.h"
+
+using namespace process_linux;
+
+LinuxSignals::LinuxSignals()
+ : UnixSignals()
+{
+ Reset();
+}
+
+void
+LinuxSignals::Reset()
+{
+ m_signals.clear();
+
+ AddSignal (1, "SIGHUP", "HUP", false, true , true , "hangup");
+ AddSignal (2, "SIGINT", "INT", true , true , true , "interrupt");
+ AddSignal (3, "SIGQUIT", "QUIT", false, true , true , "quit");
+ AddSignal (4, "SIGILL", "ILL", false, true , true , "illegal instruction");
+ AddSignal (5, "SIGTRAP", "TRAP", true , true , true , "trace trap (not reset when caught)");
+ AddSignal (6, "SIGABRT", "ABRT", false, true , true , "abort()");
+ AddSignal (6, "SIGIOT", "IOT", false, true , true , "IOT trap");
+ AddSignal (7, "SIGBUS", "BUS", false, true , true , "bus error");
+ AddSignal (8, "SIGFPE", "FPE", false, true , true , "floating point exception");
+ AddSignal (9, "SIGKILL", "KILL", false, true , true , "kill");
+ AddSignal (10, "SIGUSR1", "USR1", false, true , true , "user defined signal 1");
+ AddSignal (11, "SIGSEGV", "SEGV", false, true , true , "segmentation violation");
+ AddSignal (12, "SIGUSR2", "USR2", false, true , true , "user defined signal 2");
+ AddSignal (13, "SIGPIPE", "PIPE", false, true , true , "write to pipe with reading end closed");
+ AddSignal (14, "SIGALRM", "ALRM", false, false, false, "alarm");
+ AddSignal (15, "SIGTERM", "TERM", false, true , true , "termination requested");
+ AddSignal (16, "SIGSTKFLT", "STKFLT", false, true , true , "stack fault");
+ AddSignal (16, "SIGCLD", "CLD", false, false, true , "same as SIGCHLD");
+ AddSignal (17, "SIGCHLD", "CHLD", false, false, true , "child status has changed");
+ AddSignal (18, "SIGCONT", "CONT", false, true , true , "process continue");
+ AddSignal (19, "SIGSTOP", "STOP", true , true , true , "process stop");
+ AddSignal (20, "SIGTSTP", "TSTP", false, true , true , "tty stop");
+ AddSignal (21, "SIGTTIN", "TTIN", false, true , true , "background tty read");
+ AddSignal (22, "SIGTTOU", "TTOU", false, true , true , "background tty write");
+ AddSignal (23, "SIGURG", "URG", false, true , true , "urgent data on socket");
+ AddSignal (24, "SIGXCPU", "XCPU", false, true , true , "CPU resource exceeded");
+ AddSignal (25, "SIGXFSZ", "XFSZ", false, true , true , "file size limit exceeded");
+ AddSignal (26, "SIGVTALRM", "VTALRM", false, true , true , "virtual time alarm");
+ AddSignal (27, "SIGPROF", "PROF", false, true , true , "profiling time alarm");
+ AddSignal (28, "SIGWINCH", "WINCH", false, true , true , "window size changes");
+ AddSignal (29, "SIGPOLL", "POLL", false, true , true , "pollable event");
+ AddSignal (29, "SIGIO", "IO", false, true , true , "input/output ready");
+ AddSignal (30, "SIGPWR", "PWR", false, true , true , "power failure");
+ AddSignal (31, "SIGSYS", "SYS", false, true , true , "invalid system call");
+}
diff --git a/source/Plugins/Process/Utility/LinuxSignals.h b/source/Plugins/Process/Utility/LinuxSignals.h
new file mode 100644
index 000000000000..9645b3d8725a
--- /dev/null
+++ b/source/Plugins/Process/Utility/LinuxSignals.h
@@ -0,0 +1,35 @@
+//===-- LinuxSignals.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_LinuxSignals_H_
+#define liblldb_LinuxSignals_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/UnixSignals.h"
+
+namespace process_linux
+{
+
+ /// Linux specific set of Unix signals.
+ class LinuxSignals
+ : public lldb_private::UnixSignals
+ {
+ public:
+ LinuxSignals();
+
+ private:
+ void
+ Reset();
+ };
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
index 4d77b6f20fdc..4138a6aaa2aa 100644
--- a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
@@ -37,6 +37,8 @@
#include "ARM_GCC_Registers.h"
#include "ARM_DWARF_Registers.h"
+#include "llvm/ADT/STLExtras.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -399,7 +401,7 @@ g_exc_regnums[] =
exc_far,
};
-static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
void
RegisterContextDarwin_arm::InvalidateAllRegisters ()
@@ -438,9 +440,9 @@ RegisterContextDarwin_arm::GetRegisterInfos ()
// Number of registers in each register set
-const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t);
-const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t);
-const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t);
+const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums);
+const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums);
+const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums);
//----------------------------------------------------------------------
// Register set definitions. The first definitions at register set index
@@ -454,7 +456,7 @@ static const RegisterSet g_reg_sets[] =
{ "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
};
-const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet);
+const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets);
size_t
@@ -473,7 +475,7 @@ RegisterContextDarwin_arm::GetRegisterSet (size_t reg_set)
//----------------------------------------------------------------------
-// Register information defintions for 32 bit i386.
+// Register information definitions for 32 bit i386.
//----------------------------------------------------------------------
int
RegisterContextDarwin_arm::GetSetForNativeRegNum (int reg)
@@ -864,7 +866,7 @@ RegisterContextDarwin_arm::WriteAllRegisterValues (const lldb::DataBufferSP &dat
}
uint32_t
-RegisterContextDarwin_arm::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+RegisterContextDarwin_arm::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t reg)
{
if (kind == eRegisterKindGeneric)
{
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
index 0bf204f57c80..23134efd43e6 100644
--- a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
@@ -87,7 +87,7 @@ public:
WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
virtual uint32_t
- ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
virtual uint32_t
NumSupportedHardwareBreakpoints ();
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
new file mode 100644
index 000000000000..e08a87369e4d
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
@@ -0,0 +1,944 @@
+//===-- RegisterContextDarwin_arm64.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+#include "RegisterContextDarwin_arm64.h"
+
+// C Includes
+#include <mach/mach_types.h>
+#include <mach/thread_act.h>
+#include <sys/sysctl.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+
+#include "Plugins/Process/Utility/InstructionUtils.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "ARM64_GCC_Registers.h"
+#include "ARM64_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextDarwin_arm64::RegisterContextDarwin_arm64(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext(thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_arm64::~RegisterContextDarwin_arm64()
+{
+}
+
+
+#define GPR_OFFSET(idx) ((idx) * 8)
+#define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::GPR, reg))
+
+#define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextDarwin_arm64::GPR))
+#define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::FPU, reg))
+
+#define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::EXC, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU))
+#define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::DBG, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC))
+
+//-----------------------------------------------------------------------------
+// Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure.
+//-----------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_ARM64_STRUCT
+#include "RegisterInfos_arm64.h"
+#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT
+
+// General purpose registers
+static uint32_t
+g_gpr_regnums[] =
+{
+ gpr_x0,
+ gpr_x1,
+ gpr_x2,
+ gpr_x3,
+ gpr_x4,
+ gpr_x5,
+ gpr_x6,
+ gpr_x7,
+ gpr_x8,
+ gpr_x9,
+ gpr_x10,
+ gpr_x11,
+ gpr_x12,
+ gpr_x13,
+ gpr_x14,
+ gpr_x15,
+ gpr_x16,
+ gpr_x17,
+ gpr_x18,
+ gpr_x19,
+ gpr_x20,
+ gpr_x21,
+ gpr_x22,
+ gpr_x23,
+ gpr_x24,
+ gpr_x25,
+ gpr_x26,
+ gpr_x27,
+ gpr_x28,
+ gpr_fp,
+ gpr_lr,
+ gpr_sp,
+ gpr_pc,
+ gpr_cpsr
+};
+
+// Floating point registers
+static uint32_t
+g_fpu_regnums[] =
+{
+ fpu_v0,
+ fpu_v1,
+ fpu_v2,
+ fpu_v3,
+ fpu_v4,
+ fpu_v5,
+ fpu_v6,
+ fpu_v7,
+ fpu_v8,
+ fpu_v9,
+ fpu_v10,
+ fpu_v11,
+ fpu_v12,
+ fpu_v13,
+ fpu_v14,
+ fpu_v15,
+ fpu_v16,
+ fpu_v17,
+ fpu_v18,
+ fpu_v19,
+ fpu_v20,
+ fpu_v21,
+ fpu_v22,
+ fpu_v23,
+ fpu_v24,
+ fpu_v25,
+ fpu_v26,
+ fpu_v27,
+ fpu_v28,
+ fpu_v29,
+ fpu_v30,
+ fpu_v31,
+ fpu_fpsr,
+ fpu_fpcr
+};
+
+// Exception registers
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_far,
+ exc_esr,
+ exc_exception
+};
+
+static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos_arm64);
+
+void
+RegisterContextDarwin_arm64::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_arm64::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm64::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos_arm64[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextDarwin_arm64::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm64::GetRegisterInfos ()
+{
+ return g_register_infos_arm64;
+}
+
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums);
+const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums);
+const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets);
+
+
+size_t
+RegisterContextDarwin_arm64::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_arm64::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Register information definitions for arm64
+//----------------------------------------------------------------------
+int
+RegisterContextDarwin_arm64::GetSetForNativeRegNum (int reg)
+{
+ if (reg < fpu_v0)
+ return GPRRegSet;
+ else if (reg < exc_far)
+ return FPURegSet;
+ else if (reg < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+int
+RegisterContextDarwin_arm64::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm64::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm64::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm64::ReadDBG (bool force)
+{
+ int set = DBGRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadDBG(GetThreadID(), set, dbg));
+ }
+ return GetError(DBGRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm64::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError(GPRRegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm64::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError(FPURegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm64::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError(EXCRegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm64::WriteDBG ()
+{
+ int set = DBGRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteDBG(GetThreadID(), set, dbg));
+ SetError (set, Read, -1);
+ return GetError(DBGRegSet, Write);
+}
+
+
+int
+RegisterContextDarwin_arm64::ReadRegisterSet (uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR(force);
+ case FPURegSet: return ReadFPU(force);
+ case EXCRegSet: return ReadEXC(force);
+ case DBGRegSet: return ReadDBG(force);
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+int
+RegisterContextDarwin_arm64::WriteRegisterSet (uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ if (RegisterSetIsCached(set))
+ {
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR();
+ case FPURegSet: return WriteFPU();
+ case EXCRegSet: return WriteEXC();
+ case DBGRegSet: return WriteDBG();
+ default: break;
+ }
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+void
+RegisterContextDarwin_arm64::LogDBGRegisters (Log *log, const DBG& dbg)
+{
+ if (log)
+ {
+ for (uint32_t i=0; i<16; i++)
+ log->Printf("BVR%-2u/BCR%-2u = { 0x%8.8llx, 0x%8.8llx } WVR%-2u/WCR%-2u = { 0x%8.8llx, 0x%8.8llx }",
+ i, i, dbg.bvr[i], dbg.bcr[i],
+ i, i, dbg.wvr[i], dbg.wcr[i]);
+ }
+}
+
+
+bool
+RegisterContextDarwin_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_arm64::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_x0:
+ case gpr_x1:
+ case gpr_x2:
+ case gpr_x3:
+ case gpr_x4:
+ case gpr_x5:
+ case gpr_x6:
+ case gpr_x7:
+ case gpr_x8:
+ case gpr_x9:
+ case gpr_x10:
+ case gpr_x11:
+ case gpr_x12:
+ case gpr_x13:
+ case gpr_x14:
+ case gpr_x15:
+ case gpr_x16:
+ case gpr_x17:
+ case gpr_x18:
+ case gpr_x19:
+ case gpr_x20:
+ case gpr_x21:
+ case gpr_x22:
+ case gpr_x23:
+ case gpr_x24:
+ case gpr_x25:
+ case gpr_x26:
+ case gpr_x27:
+ case gpr_x28:
+ case gpr_fp:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ value.SetUInt64 (gpr.x[reg - gpr_x0]);
+ break;
+
+ case fpu_v0:
+ case fpu_v1:
+ case fpu_v2:
+ case fpu_v3:
+ case fpu_v4:
+ case fpu_v5:
+ case fpu_v6:
+ case fpu_v7:
+ case fpu_v8:
+ case fpu_v9:
+ case fpu_v10:
+ case fpu_v11:
+ case fpu_v12:
+ case fpu_v13:
+ case fpu_v14:
+ case fpu_v15:
+ case fpu_v16:
+ case fpu_v17:
+ case fpu_v18:
+ case fpu_v19:
+ case fpu_v20:
+ case fpu_v21:
+ case fpu_v22:
+ case fpu_v23:
+ case fpu_v24:
+ case fpu_v25:
+ case fpu_v26:
+ case fpu_v27:
+ case fpu_v28:
+ case fpu_v29:
+ case fpu_v30:
+ case fpu_v31:
+ value.SetBytes(fpu.v[reg].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder());
+ break;
+
+ case fpu_fpsr:
+ value.SetUInt32 (fpu.fpsr);
+ break;
+
+ case fpu_fpcr:
+ value.SetUInt32 (fpu.fpcr);
+ break;
+
+ case exc_exception:
+ value.SetUInt32 (exc.exception);
+ break;
+ case exc_esr:
+ value.SetUInt32 (exc.esr);
+ break;
+ case exc_far:
+ value.SetUInt64 (exc.far);
+ break;
+
+ default:
+ value.SetValueToInvalid();
+ return false;
+
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_arm64::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_x0:
+ case gpr_x1:
+ case gpr_x2:
+ case gpr_x3:
+ case gpr_x4:
+ case gpr_x5:
+ case gpr_x6:
+ case gpr_x7:
+ case gpr_x8:
+ case gpr_x9:
+ case gpr_x10:
+ case gpr_x11:
+ case gpr_x12:
+ case gpr_x13:
+ case gpr_x14:
+ case gpr_x15:
+ case gpr_x16:
+ case gpr_x17:
+ case gpr_x18:
+ case gpr_x19:
+ case gpr_x20:
+ case gpr_x21:
+ case gpr_x22:
+ case gpr_x23:
+ case gpr_x24:
+ case gpr_x25:
+ case gpr_x26:
+ case gpr_x27:
+ case gpr_x28:
+ case gpr_fp:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ gpr.x[reg - gpr_x0] = value.GetAsUInt64();
+ break;
+
+ case fpu_v0:
+ case fpu_v1:
+ case fpu_v2:
+ case fpu_v3:
+ case fpu_v4:
+ case fpu_v5:
+ case fpu_v6:
+ case fpu_v7:
+ case fpu_v8:
+ case fpu_v9:
+ case fpu_v10:
+ case fpu_v11:
+ case fpu_v12:
+ case fpu_v13:
+ case fpu_v14:
+ case fpu_v15:
+ case fpu_v16:
+ case fpu_v17:
+ case fpu_v18:
+ case fpu_v19:
+ case fpu_v20:
+ case fpu_v21:
+ case fpu_v22:
+ case fpu_v23:
+ case fpu_v24:
+ case fpu_v25:
+ case fpu_v26:
+ case fpu_v27:
+ case fpu_v28:
+ case fpu_v29:
+ case fpu_v30:
+ case fpu_v31:
+ ::memcpy (fpu.v[reg].bytes, value.GetBytes(), value.GetByteSize());
+ break;
+
+ case fpu_fpsr:
+ fpu.fpsr = value.GetAsUInt32();
+ break;
+
+ case fpu_fpcr:
+ fpu.fpcr = value.GetAsUInt32();
+ break;
+
+ case exc_exception:
+ exc.exception = value.GetAsUInt32();
+ break;
+ case exc_esr:
+ exc.esr = value.GetAsUInt32();
+ break;
+ case exc_far:
+ exc.far = value.GetAsUInt64();
+ break;
+
+ default:
+ return false;
+
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextDarwin_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == KERN_SUCCESS &&
+ ReadFPU (false) == KERN_SUCCESS &&
+ ReadEXC (false) == KERN_SUCCESS)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDarwin_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteFPU() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteEXC() == KERN_SUCCESS)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+uint32_t
+RegisterContextDarwin_arm64::ConvertRegisterKindToRegisterNumber (RegisterKind kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_pc;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_sp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_fp;
+ case LLDB_REGNUM_GENERIC_RA: return gpr_lr;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_cpsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case arm64_dwarf::x0: return gpr_x0;
+ case arm64_dwarf::x1: return gpr_x1;
+ case arm64_dwarf::x2: return gpr_x2;
+ case arm64_dwarf::x3: return gpr_x3;
+ case arm64_dwarf::x4: return gpr_x4;
+ case arm64_dwarf::x5: return gpr_x5;
+ case arm64_dwarf::x6: return gpr_x6;
+ case arm64_dwarf::x7: return gpr_x7;
+ case arm64_dwarf::x8: return gpr_x8;
+ case arm64_dwarf::x9: return gpr_x9;
+ case arm64_dwarf::x10: return gpr_x10;
+ case arm64_dwarf::x11: return gpr_x11;
+ case arm64_dwarf::x12: return gpr_x12;
+ case arm64_dwarf::x13: return gpr_x13;
+ case arm64_dwarf::x14: return gpr_x14;
+ case arm64_dwarf::x15: return gpr_x15;
+ case arm64_dwarf::x16: return gpr_x16;
+ case arm64_dwarf::x17: return gpr_x17;
+ case arm64_dwarf::x18: return gpr_x18;
+ case arm64_dwarf::x19: return gpr_x19;
+ case arm64_dwarf::x20: return gpr_x20;
+ case arm64_dwarf::x21: return gpr_x21;
+ case arm64_dwarf::x22: return gpr_x22;
+ case arm64_dwarf::x23: return gpr_x23;
+ case arm64_dwarf::x24: return gpr_x24;
+ case arm64_dwarf::x25: return gpr_x25;
+ case arm64_dwarf::x26: return gpr_x26;
+ case arm64_dwarf::x27: return gpr_x27;
+ case arm64_dwarf::x28: return gpr_x28;
+
+ case arm64_dwarf::fp: return gpr_fp;
+ case arm64_dwarf::sp: return gpr_sp;
+ case arm64_dwarf::lr: return gpr_lr;
+ case arm64_dwarf::pc: return gpr_pc;
+ case arm64_dwarf::cpsr: return gpr_cpsr;
+
+ case arm64_dwarf::v0: return fpu_v0;
+ case arm64_dwarf::v1: return fpu_v1;
+ case arm64_dwarf::v2: return fpu_v2;
+ case arm64_dwarf::v3: return fpu_v3;
+ case arm64_dwarf::v4: return fpu_v4;
+ case arm64_dwarf::v5: return fpu_v5;
+ case arm64_dwarf::v6: return fpu_v6;
+ case arm64_dwarf::v7: return fpu_v7;
+ case arm64_dwarf::v8: return fpu_v8;
+ case arm64_dwarf::v9: return fpu_v9;
+ case arm64_dwarf::v10: return fpu_v10;
+ case arm64_dwarf::v11: return fpu_v11;
+ case arm64_dwarf::v12: return fpu_v12;
+ case arm64_dwarf::v13: return fpu_v13;
+ case arm64_dwarf::v14: return fpu_v14;
+ case arm64_dwarf::v15: return fpu_v15;
+ case arm64_dwarf::v16: return fpu_v16;
+ case arm64_dwarf::v17: return fpu_v17;
+ case arm64_dwarf::v18: return fpu_v18;
+ case arm64_dwarf::v19: return fpu_v19;
+ case arm64_dwarf::v20: return fpu_v20;
+ case arm64_dwarf::v21: return fpu_v21;
+ case arm64_dwarf::v22: return fpu_v22;
+ case arm64_dwarf::v23: return fpu_v23;
+ case arm64_dwarf::v24: return fpu_v24;
+ case arm64_dwarf::v25: return fpu_v25;
+ case arm64_dwarf::v26: return fpu_v26;
+ case arm64_dwarf::v27: return fpu_v27;
+ case arm64_dwarf::v28: return fpu_v28;
+ case arm64_dwarf::v29: return fpu_v29;
+ case arm64_dwarf::v30: return fpu_v30;
+ case arm64_dwarf::v31: return fpu_v31;
+
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC)
+ {
+ switch (reg)
+ {
+ case arm64_gcc::x0: return gpr_x0;
+ case arm64_gcc::x1: return gpr_x1;
+ case arm64_gcc::x2: return gpr_x2;
+ case arm64_gcc::x3: return gpr_x3;
+ case arm64_gcc::x4: return gpr_x4;
+ case arm64_gcc::x5: return gpr_x5;
+ case arm64_gcc::x6: return gpr_x6;
+ case arm64_gcc::x7: return gpr_x7;
+ case arm64_gcc::x8: return gpr_x8;
+ case arm64_gcc::x9: return gpr_x9;
+ case arm64_gcc::x10: return gpr_x10;
+ case arm64_gcc::x11: return gpr_x11;
+ case arm64_gcc::x12: return gpr_x12;
+ case arm64_gcc::x13: return gpr_x13;
+ case arm64_gcc::x14: return gpr_x14;
+ case arm64_gcc::x15: return gpr_x15;
+ case arm64_gcc::x16: return gpr_x16;
+ case arm64_gcc::x17: return gpr_x17;
+ case arm64_gcc::x18: return gpr_x18;
+ case arm64_gcc::x19: return gpr_x19;
+ case arm64_gcc::x20: return gpr_x20;
+ case arm64_gcc::x21: return gpr_x21;
+ case arm64_gcc::x22: return gpr_x22;
+ case arm64_gcc::x23: return gpr_x23;
+ case arm64_gcc::x24: return gpr_x24;
+ case arm64_gcc::x25: return gpr_x25;
+ case arm64_gcc::x26: return gpr_x26;
+ case arm64_gcc::x27: return gpr_x27;
+ case arm64_gcc::x28: return gpr_x28;
+ case arm64_gcc::fp: return gpr_fp;
+ case arm64_gcc::sp: return gpr_sp;
+ case arm64_gcc::lr: return gpr_lr;
+ case arm64_gcc::pc: return gpr_pc;
+ case arm64_gcc::cpsr: return gpr_cpsr;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+uint32_t
+RegisterContextDarwin_arm64::NumSupportedHardwareWatchpoints ()
+{
+#if defined (__arm64__) || defined (__aarch64__)
+ // autodetect how many watchpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX;
+ if (g_num_supported_hw_watchpoints == UINT32_MAX)
+ {
+ size_t len;
+ uint32_t n = 0;
+ len = sizeof (n);
+ if (::sysctlbyname("hw.optional.watchpoint", &n, &len, NULL, 0) == 0)
+ {
+ g_num_supported_hw_watchpoints = n;
+ }
+ }
+ return g_num_supported_hw_watchpoints;
+#else
+ // TODO: figure out remote case here!
+ return 2;
+#endif
+}
+
+
+uint32_t
+RegisterContextDarwin_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write);
+
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ // Can't watch zero bytes
+ if (size == 0)
+ return LLDB_INVALID_INDEX32;
+
+ // We must watch for either read or write
+ if (read == false && write == false)
+ return LLDB_INVALID_INDEX32;
+
+ // Can't watch more than 4 bytes per WVR/WCR pair
+ if (size > 4)
+ return LLDB_INVALID_INDEX32;
+
+ // We can only watch up to four bytes that follow a 4 byte aligned address
+ // per watchpoint register pair. Since we have at most so we can only watch
+ // until the next 4 byte boundary and we need to make sure we can properly
+ // encode this.
+ uint32_t addr_word_offset = addr % 4;
+// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset);
+
+ uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset;
+// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask);
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Read the debug state
+ int kret = ReadDBG (false);
+
+ if (kret == KERN_SUCCESS)
+ {
+ // Check to make sure we have the needed hardware support
+ uint32_t i = 0;
+
+ for (i=0; i<num_hw_watchpoints; ++i)
+ {
+ if ((dbg.wcr[i] & WCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_watchpoints)
+ {
+ // Make the byte_mask into a valid Byte Address Select mask
+ uint32_t byte_address_select = byte_mask << 5;
+ // Make sure bits 1:0 are clear in our address
+ dbg.wvr[i] = addr & ~((lldb::addr_t)3);
+ dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA that we will watch
+ S_USER | // Stop only in user mode
+ (read ? WCR_LOAD : 0) | // Stop on read access?
+ (write ? WCR_STORE : 0) | // Stop on write access?
+ WCR_ENABLE; // Enable this watchpoint;
+
+ kret = WriteDBG();
+// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ else
+ {
+// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints);
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextDarwin_arm64::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ int kret = ReadDBG (false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareWatchpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ dbg.wcr[hw_index] = 0;
+// if (log) log->Printf ("RegisterContextDarwin_arm64::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x",
+// hw_index,
+// hw_index,
+// dbg.wvr[hw_index],
+// hw_index,
+// dbg.wcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h
new file mode 100644
index 000000000000..aeac15e9b09a
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h
@@ -0,0 +1,296 @@
+//===-- RegisterContextDarwin_arm64.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_RegisterContextDarwin_arm64_h_
+#define liblldb_RegisterContextDarwin_arm64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+// Break only in privileged or user mode
+#define S_RSVD ((uint32_t)(0u << 1))
+#define S_PRIV ((uint32_t)(1u << 1))
+#define S_USER ((uint32_t)(2u << 1))
+#define S_PRIV_USER ((S_PRIV) | (S_USER))
+
+#define WCR_ENABLE ((uint32_t)(1u))
+
+// Watchpoint load/store
+#define WCR_LOAD ((uint32_t)(1u << 3))
+#define WCR_STORE ((uint32_t)(1u << 4))
+
+class RegisterContextDarwin_arm64 : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextDarwin_arm64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_arm64();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
+
+ virtual uint32_t
+ NumSupportedHardwareWatchpoints ();
+
+ virtual uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write);
+
+ virtual bool
+ ClearHardwareWatchpoint (uint32_t hw_index);
+
+ // mirrors <mach/arm/thread_status.h> arm_thread_state64_t
+ struct GPR
+ {
+ uint64_t x[29]; // x0-x28
+ uint64_t fp; // x29
+ uint64_t lr; // x30
+ uint64_t sp; // x31
+ uint64_t pc; // pc
+ uint32_t cpsr; // cpsr
+ };
+
+
+ struct VReg
+ {
+ uint8_t bytes[16];
+ };
+
+ // mirrors <mach/arm/thread_status.h> arm_neon_state64_t
+ struct FPU
+ {
+ VReg v[32];
+ uint32_t fpsr;
+ uint32_t fpcr;
+ };
+
+ // mirrors <mach/arm/thread_status.h> arm_exception_state64_t
+ struct EXC
+ {
+ uint64_t far; // Virtual Fault Address
+ uint32_t esr; // Exception syndrome
+ uint32_t exception; // number of arm exception token
+ };
+
+ // mirrors <mach/arm/thread_status.h> arm_debug_state64_t
+ struct DBG
+ {
+ uint64_t bvr[16];
+ uint64_t bcr[16];
+ uint64_t wvr[16];
+ uint64_t wcr[16];
+ uint64_t mdscr_el1;
+ };
+
+ static void
+ LogDBGRegisters (lldb_private::Log *log, const DBG& dbg);
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 6, // ARM_THREAD_STATE64
+ FPURegSet = 17, // ARM_NEON_STATE64
+ EXCRegSet = 7, // ARM_EXCEPTION_STATE64
+ DBGRegSet = 15 // ARM_DEBUG_STATE64
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t), // ARM_THREAD_STATE64_COUNT
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t), // ARM_NEON_STATE64_COUNT
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t), // ARM_EXCEPTION_STATE64_COUNT
+ DBGWordCount = sizeof(DBG)/sizeof(uint32_t) // ARM_DEBUG_STATE64_COUNT
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ DBG dbg;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+ int dbg_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ case DBGRegSet: return dbg_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, int err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ case DBGRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == 0;
+ }
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ ReadDBG (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ int
+ WriteDBG ();
+
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+ {
+ return -1;
+ }
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ virtual int
+ DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextDarwin_arm64_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
index a94d1f538a28..08144bf7ec26 100644
--- a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
@@ -19,6 +19,7 @@
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Host/Endian.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
// Support building against older versions of LLVM, this macro was added
@@ -281,7 +282,7 @@ static RegisterInfo g_register_infos[] =
{ DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL}
};
-static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
void
RegisterContextDarwin_i386::InvalidateAllRegisters ()
@@ -384,9 +385,9 @@ g_exc_regnums[] =
};
// Number of registers in each register set
-const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t);
-const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t);
-const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t);
+const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums);
+const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums);
+const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums);
//----------------------------------------------------------------------
// Register set definitions. The first definitions at register set index
@@ -400,7 +401,7 @@ static const RegisterSet g_reg_sets[] =
{ "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
};
-const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet);
+const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets);
size_t
@@ -843,7 +844,7 @@ RegisterContextDarwin_i386::WriteAllRegisterValues (const lldb::DataBufferSP &da
uint32_t
-RegisterContextDarwin_i386::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+RegisterContextDarwin_i386::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t reg)
{
if (kind == eRegisterKindGeneric)
{
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
index a588494f9dcf..1d03feb9f3dd 100644
--- a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
@@ -55,7 +55,7 @@ public:
WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
virtual uint32_t
- ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
virtual bool
HardwareSingleStep (bool enable);
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
index 433782fe20c0..54124d187d54 100644
--- a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
@@ -9,6 +9,7 @@
// C Includes
+#include <inttypes.h> // PRIx64
#include <stdarg.h>
#include <stddef.h> // offsetof
@@ -20,6 +21,7 @@
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Host/Endian.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
// Support building against older versions of LLVM, this macro was added
@@ -317,7 +319,7 @@ static RegisterInfo g_register_infos[] =
{ DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL}
};
-static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
void
@@ -431,9 +433,9 @@ g_exc_regnums[] =
};
// Number of registers in each register set
-const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t);
-const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t);
-const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t);
+const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums);
+const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums);
+const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums);
//----------------------------------------------------------------------
// Register set definitions. The first definitions at register set index
@@ -447,7 +449,7 @@ static const RegisterSet g_reg_sets[] =
{ "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
};
-const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet);
+const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets);
size_t
@@ -902,7 +904,7 @@ RegisterContextDarwin_x86_64::WriteAllRegisterValues (const lldb::DataBufferSP &
uint32_t
-RegisterContextDarwin_x86_64::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+RegisterContextDarwin_x86_64::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t reg)
{
if (kind == eRegisterKindGeneric)
{
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
index 4b8127af997c..09e35e9c423e 100644
--- a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
@@ -54,7 +54,7 @@ public:
WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
virtual uint32_t
- ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
virtual bool
HardwareSingleStep (bool enable);
diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.cpp b/source/Plugins/Process/Utility/RegisterContextDummy.cpp
index 1e282ce74f2e..329b0a7968a2 100644
--- a/source/Plugins/Process/Utility/RegisterContextDummy.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextDummy.cpp
@@ -129,7 +129,7 @@ RegisterContextDummy::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
}
uint32_t
-RegisterContextDummy::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+RegisterContextDummy::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
{
if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC)
return 0;
diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.h b/source/Plugins/Process/Utility/RegisterContextDummy.h
index ee8d5a134bbc..ddf466713048 100644
--- a/source/Plugins/Process/Utility/RegisterContextDummy.h
+++ b/source/Plugins/Process/Utility/RegisterContextDummy.h
@@ -60,7 +60,7 @@ public:
WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
virtual uint32_t
- ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
private:
//------------------------------------------------------------------
diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
index 01c9bb4cde8f..185ba26944fe 100644
--- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
@@ -62,27 +62,27 @@ RegisterContextFreeBSD_i386::RegisterContextFreeBSD_i386(const ArchSpec &target_
{
}
-RegisterContextFreeBSD_i386::~RegisterContextFreeBSD_i386()
-{
-}
-
size_t
-RegisterContextFreeBSD_i386::GetGPRSize()
+RegisterContextFreeBSD_i386::GetGPRSize() const
{
return sizeof(GPR);
}
const RegisterInfo *
-RegisterContextFreeBSD_i386::GetRegisterInfo()
+RegisterContextFreeBSD_i386::GetRegisterInfo() const
{
- switch (m_target_arch.GetCore())
+ switch (m_target_arch.GetMachine())
{
- case ArchSpec::eCore_x86_32_i386:
- case ArchSpec::eCore_x86_32_i486:
- case ArchSpec::eCore_x86_32_i486sx:
+ case llvm::Triple::x86:
return g_register_infos_i386;
default:
assert(false && "Unhandled target architecture.");
return NULL;
}
}
+
+uint32_t
+RegisterContextFreeBSD_i386::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_i386) / sizeof (g_register_infos_i386 [0]));
+}
diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.h b/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h
index 4ec2ad3e9706..62792c02e2b9 100644
--- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.h
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h
@@ -13,17 +13,19 @@
#include "RegisterContextPOSIX.h"
class RegisterContextFreeBSD_i386
- : public RegisterInfoInterface
+ : public lldb_private::RegisterInfoInterface
{
public:
RegisterContextFreeBSD_i386(const lldb_private::ArchSpec &target_arch);
- virtual ~RegisterContextFreeBSD_i386();
size_t
- GetGPRSize();
+ GetGPRSize() const override;
const lldb_private::RegisterInfo *
- GetRegisterInfo();
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
};
#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp
index 4714251fd2dc..c31b0ee7de53 100644
--- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp
@@ -71,20 +71,23 @@ RegisterContextFreeBSD_mips64::RegisterContextFreeBSD_mips64(const ArchSpec &tar
{
}
-RegisterContextFreeBSD_mips64::~RegisterContextFreeBSD_mips64()
-{
-}
-
size_t
-RegisterContextFreeBSD_mips64::GetGPRSize()
+RegisterContextFreeBSD_mips64::GetGPRSize() const
{
return sizeof(GPR);
}
const RegisterInfo *
-RegisterContextFreeBSD_mips64::GetRegisterInfo()
+RegisterContextFreeBSD_mips64::GetRegisterInfo() const
{
assert (m_target_arch.GetCore() == ArchSpec::eCore_mips64);
return g_register_infos_mips64;
}
+uint32_t
+RegisterContextFreeBSD_mips64::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_mips64) / sizeof (g_register_infos_mips64 [0]));
+}
+
+
diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.h b/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h
index 9ee767955347..f9a3ce09c5b1 100644
--- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.h
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h
@@ -13,17 +13,19 @@
#include "RegisterContextPOSIX.h"
class RegisterContextFreeBSD_mips64:
- public RegisterInfoInterface
+ public lldb_private::RegisterInfoInterface
{
public:
RegisterContextFreeBSD_mips64(const lldb_private::ArchSpec &target_arch);
- virtual ~RegisterContextFreeBSD_mips64();
size_t
- GetGPRSize();
+ GetGPRSize() const override;
const lldb_private::RegisterInfo *
- GetRegisterInfo();
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
};
#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
index 2162aaffff18..257de7198590 100644
--- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
@@ -67,10 +67,17 @@ struct dbreg {
#include "RegisterInfos_x86_64.h"
#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+static std::vector<lldb_private::RegisterInfo>&
+GetSharedRegisterInfoVector ()
+{
+ static std::vector<lldb_private::RegisterInfo> register_infos;
+ return register_infos;
+}
+
static const RegisterInfo *
GetRegisterInfo_i386(const lldb_private::ArchSpec& arch)
{
- static std::vector<lldb_private::RegisterInfo> g_register_infos;
+ static std::vector<lldb_private::RegisterInfo> g_register_infos (GetSharedRegisterInfoVector ());
// Allocate RegisterInfo only once
if (g_register_infos.empty())
@@ -92,35 +99,61 @@ GetRegisterInfo_i386(const lldb_private::ArchSpec& arch)
return &g_register_infos[0];
}
-RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(const ArchSpec &target_arch) :
- RegisterInfoInterface(target_arch)
+static const RegisterInfo *
+PrivateGetRegisterInfoPtr (const lldb_private::ArchSpec& target_arch)
{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ return GetRegisterInfo_i386 (target_arch);
+ case llvm::Triple::x86_64:
+ return g_register_infos_x86_64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
}
-RegisterContextFreeBSD_x86_64::~RegisterContextFreeBSD_x86_64()
+static uint32_t
+PrivateGetRegisterCount (const lldb_private::ArchSpec& target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ // This vector should have already been filled.
+ assert (!GetSharedRegisterInfoVector ().empty () && "i386 register info vector not filled.");
+ return static_cast<uint32_t> (GetSharedRegisterInfoVector().size ());
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t> (sizeof (g_register_infos_x86_64) / sizeof (g_register_infos_x86_64 [0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(const ArchSpec &target_arch) :
+ lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p (PrivateGetRegisterInfoPtr (target_arch)),
+ m_register_count (PrivateGetRegisterCount (target_arch))
{
}
size_t
-RegisterContextFreeBSD_x86_64::GetGPRSize()
+RegisterContextFreeBSD_x86_64::GetGPRSize() const
{
return sizeof(GPR);
}
const RegisterInfo *
-RegisterContextFreeBSD_x86_64::GetRegisterInfo()
+RegisterContextFreeBSD_x86_64::GetRegisterInfo() const
{
- switch (m_target_arch.GetCore())
- {
- case ArchSpec::eCore_x86_32_i386:
- case ArchSpec::eCore_x86_32_i486:
- case ArchSpec::eCore_x86_32_i486sx:
- return GetRegisterInfo_i386 (m_target_arch);
- case ArchSpec::eCore_x86_64_x86_64:
- return g_register_infos_x86_64;
- default:
- assert(false && "Unhandled target architecture.");
- return NULL;
- }
+ return m_register_info_p;
+}
+
+uint32_t
+RegisterContextFreeBSD_x86_64::GetRegisterCount () const
+{
+ return m_register_count;
}
+
diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h b/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h
index 731bb0ea6bcc..21fbdb4681b3 100644
--- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h
+++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h
@@ -13,17 +13,23 @@
#include "RegisterContextPOSIX.h"
class RegisterContextFreeBSD_x86_64:
- public RegisterInfoInterface
+ public lldb_private::RegisterInfoInterface
{
public:
RegisterContextFreeBSD_x86_64(const lldb_private::ArchSpec &target_arch);
- virtual ~RegisterContextFreeBSD_x86_64();
size_t
- GetGPRSize();
+ GetGPRSize() const override;
const lldb_private::RegisterInfo *
- GetRegisterInfo();
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ const uint32_t m_register_count;
};
#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextHistory.cpp b/source/Plugins/Process/Utility/RegisterContextHistory.cpp
index b7adb202ba49..3c370103629e 100644
--- a/source/Plugins/Process/Utility/RegisterContextHistory.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextHistory.cpp
@@ -130,7 +130,7 @@ RegisterContextHistory::WriteAllRegisterValues (const lldb::DataBufferSP &data_s
}
uint32_t
-RegisterContextHistory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+RegisterContextHistory::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
{
if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC)
return 0;
diff --git a/source/Plugins/Process/Utility/RegisterContextHistory.h b/source/Plugins/Process/Utility/RegisterContextHistory.h
index 58e16080b52e..04842c62aff1 100644
--- a/source/Plugins/Process/Utility/RegisterContextHistory.h
+++ b/source/Plugins/Process/Utility/RegisterContextHistory.h
@@ -60,7 +60,7 @@ public:
WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
virtual uint32_t
- ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
private:
//------------------------------------------------------------------
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
index f209d538a712..b58e6bb607ed 100644
--- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -163,15 +163,17 @@ RegisterContextLLDB::InitializeZerothFrame()
UnwindLogMsg ("using architectural default unwind method");
}
- // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
+ // We require either a symbol or function in the symbols context to be successfully
+ // filled in or this context is of no use to us.
+ const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
if (pc_module_sp.get()
- && (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ && (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, resolve_scope, m_sym_ctx) & resolve_scope))
{
m_sym_ctx_valid = true;
}
AddressRange addr_range;
- m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range);
+ m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range);
if (IsTrapHandlerSymbol (process, m_sym_ctx))
{
@@ -216,7 +218,7 @@ RegisterContextLLDB::InitializeZerothFrame()
UnwindPlan::RowSP active_row;
int cfa_offset = 0;
- int row_register_kind = -1;
+ lldb::RegisterKind row_register_kind = eRegisterKindGeneric;
if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
{
active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
@@ -362,7 +364,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()
m_current_offset = -1;
m_current_offset_backed_up_one = -1;
addr_t cfa_regval = LLDB_INVALID_ADDRESS;
- int row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ RegisterKind row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0);
if (row.get())
{
@@ -417,18 +419,20 @@ RegisterContextLLDB::InitializeNonZerothFrame()
// a function/symbol because it is beyond the bounds of the correct
// function and there's no symbol there. ResolveSymbolContextForAddress
// will fail to find a symbol, back up the pc by 1 and re-search.
+ const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc,
- eSymbolContextFunction | eSymbolContextSymbol,
+ resolve_scope,
m_sym_ctx, resolve_tail_call_address);
- // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
- if ((resolved_scope & eSymbolContextSymbol) == eSymbolContextSymbol)
+ // We require either a symbol or function in the symbols context to be successfully
+ // filled in or this context is of no use to us.
+ if (resolve_scope & resolved_scope)
{
m_sym_ctx_valid = true;
}
AddressRange addr_range;
- if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
+ if (!m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range))
{
m_sym_ctx_valid = false;
}
@@ -461,13 +465,12 @@ RegisterContextLLDB::InitializeNonZerothFrame()
temporary_pc.SetOffset(m_current_pc.GetOffset() - 1);
m_sym_ctx.Clear(false);
m_sym_ctx_valid = false;
- if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
+
+ if (pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope)
{
- m_sym_ctx_valid = true;
- }
- if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
- {
- m_sym_ctx_valid = false;
+ if (m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range))
+ m_sym_ctx_valid = true;
}
}
@@ -510,7 +513,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()
UnwindPlan::RowSP active_row;
int cfa_offset = 0;
- int row_register_kind = -1;
+ RegisterKind row_register_kind = eRegisterKindGeneric;
// Try to get by with just the fast UnwindPlan if possible - the full UnwindPlan may be expensive to get
// (e.g. if we have to parse the entire eh_frame section of an ObjectFile for the first time.)
@@ -591,7 +594,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()
repeating_frames = true;
}
}
- if (repeating_frames && abi->FunctionCallsChangeCFA())
+ if (repeating_frames && abi && abi->FunctionCallsChangeCFA())
{
UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping");
m_frame_type = eNotAValidFrame;
@@ -707,7 +710,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
// Note, if we have a symbol context & a symbol, we don't want to follow this code path. This is
// for jumping to memory regions without any information available.
- if ((!m_sym_ctx_valid || m_sym_ctx.symbol == NULL) && behaves_like_zeroth_frame && m_current_pc.IsValid())
+ if ((!m_sym_ctx_valid || (m_sym_ctx.function == NULL && m_sym_ctx.symbol == NULL)) && behaves_like_zeroth_frame && m_current_pc.IsValid())
{
uint32_t permissions;
addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr());
@@ -791,7 +794,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
// Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions
if (behaves_like_zeroth_frame)
{
- unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one);
if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
{
if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo)
@@ -819,8 +822,8 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
// We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've
// struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible.
- unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
- if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo)
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo)
{
// We probably have an UnwindPlan created by inspecting assembly instructions, and we probably
// don't have any eh_frame instructions available.
@@ -889,7 +892,7 @@ RegisterContextLLDB::GetRegisterSet (size_t reg_set)
}
uint32_t
-RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
{
return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
}
@@ -1415,7 +1418,7 @@ RegisterContextLLDB::TryFallbackUnwindPlan ()
// where frame 0 (the "next" frame) saved that and retrieve the value.
bool
-RegisterContextLLDB::ReadGPRValue (int register_kind, uint32_t regnum, addr_t &value)
+RegisterContextLLDB::ReadGPRValue (lldb::RegisterKind register_kind, uint32_t regnum, addr_t &value)
{
if (!IsValid())
return false;
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.h b/source/Plugins/Process/Utility/RegisterContextLLDB.h
index 0a60bfe382b5..d6ecfeb68caa 100644
--- a/source/Plugins/Process/Utility/RegisterContextLLDB.h
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -67,7 +67,7 @@ public:
WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
virtual uint32_t
- ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
bool
IsValid () const;
@@ -178,7 +178,7 @@ private:
// Get the contents of a general purpose (address-size) register for this frame
// (usually retrieved from the next frame)
bool
- ReadGPRValue (int register_kind, uint32_t regnum, lldb::addr_t &value);
+ ReadGPRValue (lldb::RegisterKind register_kind, uint32_t regnum, lldb::addr_t &value);
lldb::UnwindPlanSP
GetFastUnwindPlanForFrame ();
diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp
new file mode 100644
index 000000000000..8c23e39ff013
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp
@@ -0,0 +1,89 @@
+//===-- RegisterContextLinux_arm64.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include <stddef.h>
+#include <vector>
+#include <cassert>
+
+#include "llvm/Support/Compiler.h"
+#include "lldb/lldb-defines.h"
+
+#include "RegisterContextLinux_arm64.h"
+
+// Based on RegisterContextDarwin_arm64.cpp
+#define GPR_OFFSET(idx) ((idx) * 8)
+#define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::GPR, reg))
+
+#define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextLinux_arm64::GPR))
+#define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::FPU, reg))
+
+#define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::EXC, reg) + sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU))
+#define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::DBG, reg) + sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU) + sizeof (RegisterContextLinux_arm64::EXC))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextLinux_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU) + sizeof (RegisterContextLinux_arm64::EXC))
+
+
+//-----------------------------------------------------------------------------
+// Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure.
+//-----------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_ARM64_STRUCT
+#include "RegisterInfos_arm64.h"
+#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT
+
+static const lldb_private::RegisterInfo *
+GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ return g_register_infos_arm64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+}
+
+static uint32_t
+GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ return static_cast<uint32_t>(sizeof(g_register_infos_arm64) / sizeof(g_register_infos_arm64[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextLinux_arm64::RegisterContextLinux_arm64(const lldb_private::ArchSpec &target_arch) :
+ lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p(GetRegisterInfoPtr(target_arch)),
+ m_register_info_count(GetRegisterInfoCount(target_arch))
+{
+}
+
+size_t
+RegisterContextLinux_arm64::GetGPRSize() const
+{
+ return sizeof(struct RegisterContextLinux_arm64::GPR);
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextLinux_arm64::GetRegisterInfo() const
+{
+ return m_register_info_p;
+}
+
+uint32_t
+RegisterContextLinux_arm64::GetRegisterCount() const
+{
+ return m_register_info_count;
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_arm64.h b/source/Plugins/Process/Utility/RegisterContextLinux_arm64.h
new file mode 100644
index 000000000000..a9a5a0985f25
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_arm64.h
@@ -0,0 +1,81 @@
+//===-- RegisterContextLinux_arm64.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_RegisterContextLinux_arm64_H_
+#define liblldb_RegisterContextLinux_arm64_H_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterInfoInterface.h"
+
+class RegisterContextLinux_arm64
+ : public lldb_private::RegisterInfoInterface
+{
+public:
+ // based on RegisterContextDarwin_arm64.h
+ struct GPR
+ {
+ uint64_t x[29]; // x0-x28
+ uint64_t fp; // x29
+ uint64_t lr; // x30
+ uint64_t sp; // x31
+ uint64_t pc; // pc
+ uint32_t cpsr; // cpsr
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct VReg
+ {
+ uint8_t bytes[16];
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct FPU
+ {
+ VReg v[32];
+ uint32_t fpsr;
+ uint32_t fpcr;
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct EXC
+ {
+ uint64_t far; // Virtual Fault Address
+ uint32_t esr; // Exception syndrome
+ uint32_t exception; // number of arm exception token
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct DBG
+ {
+ uint64_t bvr[16];
+ uint64_t bcr[16];
+ uint64_t wvr[16];
+ uint64_t wcr[16];
+ uint64_t mdscr_el1;
+ };
+
+ RegisterContextLinux_arm64(const lldb_private::ArchSpec &target_arch);
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_i386.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
index 0828efbc6c3c..b9b9dca07be4 100644
--- a/source/Plugins/Process/POSIX/RegisterContextLinux_i386.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
@@ -34,11 +34,39 @@ struct GPR
uint32_t ss;
};
+struct FPR_i386
+{
+ uint16_t fctrl; // FPU Control Word (fcw)
+ uint16_t fstat; // FPU Status Word (fsw)
+ uint16_t ftag; // FPU Tag Word (ftw)
+ uint16_t fop; // Last Instruction Opcode (fop)
+ union
+ {
+ struct
+ {
+ uint64_t fip; // Instruction Pointer
+ uint64_t fdp; // Data Pointer
+ } x86_64;
+ struct
+ {
+ uint32_t fioff; // FPU IP Offset (fip)
+ uint32_t fiseg; // FPU IP Selector (fcs)
+ uint32_t fooff; // FPU Operand Pointer Offset (foo)
+ uint32_t foseg; // FPU Operand Pointer Selector (fos)
+ } i386_;// Added _ in the end to avoid error with gcc defining i386 in some cases
+ } ptr;
+ uint32_t mxcsr; // MXCSR Register State
+ uint32_t mxcsrmask; // MXCSR Mask
+ MMSReg stmm[8]; // 8*16 bytes for each FP-reg = 128 bytes
+ XMMReg xmm[8]; // 8*16 bytes for each XMM-reg = 128 bytes
+ uint32_t padding[56];
+};
+
struct UserArea
{
GPR regs; // General purpose registers.
int32_t fpvalid; // True if FPU is being used.
- FXSAVE i387; // FPU registers.
+ FPR_i386 i387; // FPU registers.
uint32_t tsize; // Text segment size.
uint32_t dsize; // Data segment size.
uint32_t ssize; // Stack segment size.
@@ -54,9 +82,11 @@ struct UserArea
uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7).
};
-#define DR_SIZE sizeof(UserArea::u_debugreg[0])
+#define DR_SIZE sizeof(((UserArea*)NULL)->u_debugreg[0])
+#define DR_0_OFFSET 0xFC
#define DR_OFFSET(reg_index) \
- (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index]))
+ (DR_0_OFFSET + (reg_index * 4))
+#define FPR_SIZE(reg) sizeof(((FPR_i386*)NULL)->reg)
//---------------------------------------------------------------------------
// Include RegisterInfos_i386 to declare our g_register_infos_i386 structure.
@@ -70,27 +100,28 @@ RegisterContextLinux_i386::RegisterContextLinux_i386(const ArchSpec &target_arch
{
}
-RegisterContextLinux_i386::~RegisterContextLinux_i386()
-{
-}
-
size_t
-RegisterContextLinux_i386::GetGPRSize()
+RegisterContextLinux_i386::GetGPRSize() const
{
return sizeof(GPR);
}
const RegisterInfo *
-RegisterContextLinux_i386::GetRegisterInfo()
+RegisterContextLinux_i386::GetRegisterInfo() const
{
- switch (m_target_arch.GetCore())
+ switch (m_target_arch.GetMachine())
{
- case ArchSpec::eCore_x86_32_i386:
- case ArchSpec::eCore_x86_32_i486:
- case ArchSpec::eCore_x86_32_i486sx:
+ case llvm::Triple::x86:
return g_register_infos_i386;
default:
assert(false && "Unhandled target architecture.");
return NULL;
}
}
+
+uint32_t
+RegisterContextLinux_i386::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_i386) / sizeof (g_register_infos_i386 [0]));
+}
+
diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_i386.h b/source/Plugins/Process/Utility/RegisterContextLinux_i386.h
index 81afdbf8b1cf..f8b21fc8e87d 100644
--- a/source/Plugins/Process/POSIX/RegisterContextLinux_i386.h
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_i386.h
@@ -13,17 +13,19 @@
#include "RegisterContextPOSIX.h"
class RegisterContextLinux_i386
- : public RegisterInfoInterface
+ : public lldb_private::RegisterInfoInterface
{
public:
RegisterContextLinux_i386(const lldb_private::ArchSpec &target_arch);
- virtual ~RegisterContextLinux_i386();
size_t
- GetGPRSize();
+ GetGPRSize() const override;
const lldb_private::RegisterInfo *
- GetRegisterInfo();
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
};
#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp
index 5434ddfcf38b..74f016bd744d 100644
--- a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp
@@ -69,7 +69,7 @@ struct UserArea
uint64_t fault_address; // Control register CR3.
};
-#define DR_SIZE sizeof(UserArea::u_debugreg[0])
+#define DR_SIZE sizeof(((UserArea*)NULL)->u_debugreg[0])
#define DR_OFFSET(reg_index) \
(LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index]))
@@ -80,10 +80,17 @@ struct UserArea
#include "RegisterInfos_x86_64.h"
#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+static std::vector<lldb_private::RegisterInfo>&
+GetPrivateRegisterInfoVector ()
+{
+ static std::vector<lldb_private::RegisterInfo> g_register_infos;
+ return g_register_infos;
+}
+
static const RegisterInfo *
GetRegisterInfo_i386(const lldb_private::ArchSpec &arch)
{
- static std::vector<lldb_private::RegisterInfo> g_register_infos;
+ std::vector<lldb_private::RegisterInfo> &g_register_infos = GetPrivateRegisterInfoVector ();
// Allocate RegisterInfo only once
if (g_register_infos.empty())
@@ -105,35 +112,60 @@ GetRegisterInfo_i386(const lldb_private::ArchSpec &arch)
return &g_register_infos[0];
}
-RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(const ArchSpec &target_arch) :
- RegisterInfoInterface(target_arch)
+static const RegisterInfo *
+GetRegisterInfoPtr (const ArchSpec &target_arch)
{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ return GetRegisterInfo_i386 (target_arch);
+ case llvm::Triple::x86_64:
+ return g_register_infos_x86_64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
}
-RegisterContextLinux_x86_64::~RegisterContextLinux_x86_64()
+static uint32_t
+GetRegisterInfoCount (const ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ {
+ assert (!GetPrivateRegisterInfoVector ().empty () && "i386 register info not yet filled.");
+ return static_cast<uint32_t> (GetPrivateRegisterInfoVector ().size ());
+ }
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t> (sizeof (g_register_infos_x86_64) / sizeof (g_register_infos_x86_64 [0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(const ArchSpec &target_arch) :
+ lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p (GetRegisterInfoPtr (target_arch)),
+ m_register_info_count (GetRegisterInfoCount (target_arch))
{
}
size_t
-RegisterContextLinux_x86_64::GetGPRSize()
+RegisterContextLinux_x86_64::GetGPRSize() const
{
return sizeof(GPR);
}
const RegisterInfo *
-RegisterContextLinux_x86_64::GetRegisterInfo()
+RegisterContextLinux_x86_64::GetRegisterInfo() const
{
- switch (m_target_arch.GetCore())
- {
- case ArchSpec::eCore_x86_32_i386:
- case ArchSpec::eCore_x86_32_i486:
- case ArchSpec::eCore_x86_32_i486sx:
- return GetRegisterInfo_i386 (m_target_arch);
- case ArchSpec::eCore_x86_64_x86_64:
- return g_register_infos_x86_64;
- default:
- assert(false && "Unhandled target architecture.");
- return NULL;
- }
+ return m_register_info_p;
}
+uint32_t
+RegisterContextLinux_x86_64::GetRegisterCount () const
+{
+ return m_register_info_count;
+}
diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h b/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h
index 21c809b5dc33..7b6828661c1e 100644
--- a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h
+++ b/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h
@@ -13,17 +13,23 @@
#include "RegisterContextPOSIX.h"
class RegisterContextLinux_x86_64
- : public RegisterInfoInterface
+ : public lldb_private::RegisterInfoInterface
{
public:
RegisterContextLinux_x86_64(const lldb_private::ArchSpec &target_arch);
- virtual ~RegisterContextLinux_x86_64();
size_t
- GetGPRSize();
+ GetGPRSize() const override;
const lldb_private::RegisterInfo *
- GetRegisterInfo();
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
};
#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
index 5b6d9fe9f3bb..e246e715de86 100644
--- a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
@@ -149,7 +149,7 @@ RegisterContextMacOSXFrameBackchain::ReadRegister (const RegisterInfo *reg_info,
// TOOD: need a better way to detect when "long double" types are
// the same bytes size as "double"
-#if !defined(__arm__) && !defined(_MSC_VER) && !defined(__mips__)
+#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) && !defined(_MSC_VER) && !defined(__mips__)
case sizeof (long double):
if (sizeof (long double) == sizeof(uint32_t))
{
@@ -199,7 +199,7 @@ RegisterContextMacOSXFrameBackchain::WriteAllRegisterValues (const lldb::DataBuf
uint32_t
-RegisterContextMacOSXFrameBackchain::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+RegisterContextMacOSXFrameBackchain::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
{
return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
}
diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
index 449e053e5ef1..505b8d44a27a 100644
--- a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
+++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
@@ -63,7 +63,7 @@ public:
WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
virtual uint32_t
- ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
private:
UnwindMacOSXFrameBackchain::Cursor m_cursor;
diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/source/Plugins/Process/Utility/RegisterContextMemory.cpp
index 8c33a6814acc..40d00b1eed80 100644
--- a/source/Plugins/Process/Utility/RegisterContextMemory.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextMemory.cpp
@@ -98,7 +98,7 @@ RegisterContextMemory::GetRegisterSet (size_t reg_set)
}
uint32_t
-RegisterContextMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+RegisterContextMemory::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
{
return m_reg_infos.ConvertRegisterKindToRegisterNumber (kind, num);
}
diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.h b/source/Plugins/Process/Utility/RegisterContextMemory.h
index 8bba52c627f3..9d97dfa723be 100644
--- a/source/Plugins/Process/Utility/RegisterContextMemory.h
+++ b/source/Plugins/Process/Utility/RegisterContextMemory.h
@@ -55,7 +55,7 @@ public:
GetRegisterSet (size_t reg_set);
virtual uint32_t
- ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
//------------------------------------------------------------------
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX.h b/source/Plugins/Process/Utility/RegisterContextPOSIX.h
index 600dae73b5b7..6ddd9cfe4c21 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX.h
@@ -15,6 +15,7 @@
// Other libraries and framework includes
#include "lldb/Core/ArchSpec.h"
#include "lldb/Target/RegisterContext.h"
+#include "RegisterInfoInterface.h"
//------------------------------------------------------------------------------
/// @class POSIXBreakpointProtocol
@@ -74,25 +75,5 @@ protected:
bool m_watchpoints_initialized;
};
-//------------------------------------------------------------------------------
-/// @class RegisterInfoInterface
-///
-/// @brief RegisterInfo interface to patch RegisterInfo structure for archs.
-class RegisterInfoInterface
-{
-public:
- RegisterInfoInterface(const lldb_private::ArchSpec& target_arch) : m_target_arch(target_arch) {}
- virtual ~RegisterInfoInterface () {}
-
- virtual size_t
- GetGPRSize () = 0;
-
- virtual const lldb_private::RegisterInfo *
- GetRegisterInfo () = 0;
-
-public:
- lldb_private::ArchSpec m_target_arch;
-};
-
#endif // #ifndef liblldb_RegisterContextPOSIX_H_
diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
new file mode 100644
index 000000000000..ea54a9ad9cf4
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
@@ -0,0 +1,299 @@
+//===-- RegisterContextPOSIX_arm64.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstring>
+#include <errno.h>
+#include <stdint.h>
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_arm64.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+
+// ARM64 general purpose registers.
+const uint32_t g_gpr_regnums_arm64[] =
+{
+ gpr_x0_arm64,
+ gpr_x1_arm64,
+ gpr_x2_arm64,
+ gpr_x3_arm64,
+ gpr_x4_arm64,
+ gpr_x5_arm64,
+ gpr_x6_arm64,
+ gpr_x7_arm64,
+ gpr_x8_arm64,
+ gpr_x9_arm64,
+ gpr_x10_arm64,
+ gpr_x11_arm64,
+ gpr_x12_arm64,
+ gpr_x13_arm64,
+ gpr_x14_arm64,
+ gpr_x15_arm64,
+ gpr_x16_arm64,
+ gpr_x17_arm64,
+ gpr_x18_arm64,
+ gpr_x19_arm64,
+ gpr_x20_arm64,
+ gpr_x21_arm64,
+ gpr_x22_arm64,
+ gpr_x23_arm64,
+ gpr_x24_arm64,
+ gpr_x25_arm64,
+ gpr_x26_arm64,
+ gpr_x27_arm64,
+ gpr_x28_arm64,
+ gpr_fp_arm64,
+ gpr_lr_arm64,
+ gpr_sp_arm64,
+ gpr_pc_arm64,
+ gpr_cpsr_arm64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \
+ "g_gpr_regnums_arm64 has wrong number of register infos");
+
+// ARM64 floating point registers.
+static const uint32_t g_fpu_regnums_arm64[] =
+{
+ fpu_v0_arm64,
+ fpu_v1_arm64,
+ fpu_v2_arm64,
+ fpu_v3_arm64,
+ fpu_v4_arm64,
+ fpu_v5_arm64,
+ fpu_v6_arm64,
+ fpu_v7_arm64,
+ fpu_v8_arm64,
+ fpu_v9_arm64,
+ fpu_v10_arm64,
+ fpu_v11_arm64,
+ fpu_v12_arm64,
+ fpu_v13_arm64,
+ fpu_v14_arm64,
+ fpu_v15_arm64,
+ fpu_v16_arm64,
+ fpu_v17_arm64,
+ fpu_v18_arm64,
+ fpu_v19_arm64,
+ fpu_v20_arm64,
+ fpu_v21_arm64,
+ fpu_v22_arm64,
+ fpu_v23_arm64,
+ fpu_v24_arm64,
+ fpu_v25_arm64,
+ fpu_v26_arm64,
+ fpu_v27_arm64,
+ fpu_v28_arm64,
+ fpu_v29_arm64,
+ fpu_v30_arm64,
+ fpu_v31_arm64,
+ fpu_fpsr_arm64,
+ fpu_fpcr_arm64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \
+ "g_fpu_regnums_arm64 has wrong number of register infos");
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_register_sets = 2
+};
+
+// Register sets for ARM64.
+static const lldb_private::RegisterSet
+g_reg_sets_arm64[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers_arm64, g_gpr_regnums_arm64 },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 }
+};
+
+bool RegisterContextPOSIX_arm64::IsGPR(unsigned reg)
+{
+ return reg <= m_reg_info.last_gpr; // GPR's come first.
+}
+
+bool RegisterContextPOSIX_arm64::IsFPR(unsigned reg)
+{
+ return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
+}
+
+RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info)
+ : lldb_private::RegisterContext(thread, concrete_frame_idx)
+{
+ m_register_info_ap.reset(register_info);
+
+ switch (register_info->m_target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ m_reg_info.num_registers = k_num_registers_arm64;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64;
+ m_reg_info.last_gpr = k_last_gpr_arm64;
+ m_reg_info.first_fpr = k_first_fpr_arm64;
+ m_reg_info.last_fpr = k_last_fpr_arm64;
+ m_reg_info.first_fpr_v = fpu_v0_arm64;
+ m_reg_info.last_fpr_v = fpu_v31_arm64;
+ m_reg_info.gpr_flags = gpr_cpsr_arm64;
+ break;
+ default:
+ assert(false && "Unhandled target architecture.");
+ break;
+ }
+
+ ::memset(&m_fpr, 0, sizeof m_fpr);
+
+ // elf-core yet to support ReadFPR()
+ lldb::ProcessSP base = CalculateProcess();
+ if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
+ return;
+}
+
+RegisterContextPOSIX_arm64::~RegisterContextPOSIX_arm64()
+{
+}
+
+void
+RegisterContextPOSIX_arm64::Invalidate()
+{
+}
+
+void
+RegisterContextPOSIX_arm64::InvalidateAllRegisters()
+{
+}
+
+unsigned
+RegisterContextPOSIX_arm64::GetRegisterOffset(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned
+RegisterContextPOSIX_arm64::GetRegisterSize(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t
+RegisterContextPOSIX_arm64::GetRegisterCount()
+{
+ size_t num_registers = m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers;
+ return num_registers;
+}
+
+size_t
+RegisterContextPOSIX_arm64::GetGPRSize()
+{
+ return m_register_info_ap->GetGPRSize ();
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_arm64::GetRegisterInfo()
+{
+ // Commonly, this method is overridden and g_register_infos is copied and specialized.
+ // So, use GetRegisterInfo() rather than g_register_infos in this scope.
+ return m_register_info_ap->GetRegisterInfo ();
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_arm64::GetRegisterInfoAtIndex(size_t reg)
+{
+ if (reg < m_reg_info.num_registers)
+ return &GetRegisterInfo()[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContextPOSIX_arm64::GetRegisterSetCount()
+{
+ size_t sets = 0;
+ for (size_t set = 0; set < k_num_register_sets; ++set)
+ {
+ if (IsRegisterSetAvailable(set))
+ ++sets;
+ }
+
+ return sets;
+}
+
+const lldb_private::RegisterSet *
+RegisterContextPOSIX_arm64::GetRegisterSet(size_t set)
+{
+ if (IsRegisterSetAvailable(set))
+ {
+ switch (m_register_info_ap->m_target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ return &g_reg_sets_arm64[set];
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+const char *
+RegisterContextPOSIX_arm64::GetRegisterName(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+lldb::ByteOrder
+RegisterContextPOSIX_arm64::GetByteOrder()
+{
+ // Get the target process whose privileged thread was used for the register read.
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
+ lldb_private::Process *process = CalculateProcess().get();
+
+ if (process)
+ byte_order = process->GetByteOrder();
+ return byte_order;
+}
+
+bool
+RegisterContextPOSIX_arm64::IsRegisterSetAvailable(size_t set_index)
+{
+ return set_index < k_num_register_sets;
+}
+
+
+// Used when parsing DWARF and EH frame information and any other
+// object file sections that contain register numbers in them.
+uint32_t
+RegisterContextPOSIX_arm64::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num)
+{
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert (kind < lldb::kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
new file mode 100644
index 000000000000..3639960ef3de
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
@@ -0,0 +1,272 @@
+//===-- RegisterContextPOSIX_arm64.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_RegisterContextPOSIX_arm64_H_
+#define liblldb_RegisterContextPOSIX_arm64_H_
+
+#include "lldb/Core/Log.h"
+#include "RegisterContextPOSIX.h"
+
+class ProcessMonitor;
+
+//---------------------------------------------------------------------------
+// Internal codes for all ARM64 registers.
+//---------------------------------------------------------------------------
+enum
+{
+ k_first_gpr_arm64,
+ gpr_x0_arm64 = k_first_gpr_arm64,
+ gpr_x1_arm64,
+ gpr_x2_arm64,
+ gpr_x3_arm64,
+ gpr_x4_arm64,
+ gpr_x5_arm64,
+ gpr_x6_arm64,
+ gpr_x7_arm64,
+ gpr_x8_arm64,
+ gpr_x9_arm64,
+ gpr_x10_arm64,
+ gpr_x11_arm64,
+ gpr_x12_arm64,
+ gpr_x13_arm64,
+ gpr_x14_arm64,
+ gpr_x15_arm64,
+ gpr_x16_arm64,
+ gpr_x17_arm64,
+ gpr_x18_arm64,
+ gpr_x19_arm64,
+ gpr_x20_arm64,
+ gpr_x21_arm64,
+ gpr_x22_arm64,
+ gpr_x23_arm64,
+ gpr_x24_arm64,
+ gpr_x25_arm64,
+ gpr_x26_arm64,
+ gpr_x27_arm64,
+ gpr_x28_arm64,
+ gpr_fp_arm64,
+ gpr_lr_arm64,
+ gpr_sp_arm64,
+ gpr_pc_arm64,
+ gpr_cpsr_arm64,
+
+ k_last_gpr_arm64 = gpr_cpsr_arm64,
+
+ k_first_fpr_arm64,
+ fpu_v0_arm64 = k_first_fpr_arm64,
+ fpu_v1_arm64,
+ fpu_v2_arm64,
+ fpu_v3_arm64,
+ fpu_v4_arm64,
+ fpu_v5_arm64,
+ fpu_v6_arm64,
+ fpu_v7_arm64,
+ fpu_v8_arm64,
+ fpu_v9_arm64,
+ fpu_v10_arm64,
+ fpu_v11_arm64,
+ fpu_v12_arm64,
+ fpu_v13_arm64,
+ fpu_v14_arm64,
+ fpu_v15_arm64,
+ fpu_v16_arm64,
+ fpu_v17_arm64,
+ fpu_v18_arm64,
+ fpu_v19_arm64,
+ fpu_v20_arm64,
+ fpu_v21_arm64,
+ fpu_v22_arm64,
+ fpu_v23_arm64,
+ fpu_v24_arm64,
+ fpu_v25_arm64,
+ fpu_v26_arm64,
+ fpu_v27_arm64,
+ fpu_v28_arm64,
+ fpu_v29_arm64,
+ fpu_v30_arm64,
+ fpu_v31_arm64,
+ fpu_fpsr_arm64,
+ fpu_fpcr_arm64,
+ k_last_fpr_arm64 = fpu_fpcr_arm64,
+
+ exc_far_arm64,
+ exc_esr_arm64,
+ exc_exception_arm64,
+
+ dbg_bvr0_arm64,
+ dbg_bvr1_arm64,
+ dbg_bvr2_arm64,
+ dbg_bvr3_arm64,
+ dbg_bvr4_arm64,
+ dbg_bvr5_arm64,
+ dbg_bvr6_arm64,
+ dbg_bvr7_arm64,
+ dbg_bvr8_arm64,
+ dbg_bvr9_arm64,
+ dbg_bvr10_arm64,
+ dbg_bvr11_arm64,
+ dbg_bvr12_arm64,
+ dbg_bvr13_arm64,
+ dbg_bvr14_arm64,
+ dbg_bvr15_arm64,
+ dbg_bcr0_arm64,
+ dbg_bcr1_arm64,
+ dbg_bcr2_arm64,
+ dbg_bcr3_arm64,
+ dbg_bcr4_arm64,
+ dbg_bcr5_arm64,
+ dbg_bcr6_arm64,
+ dbg_bcr7_arm64,
+ dbg_bcr8_arm64,
+ dbg_bcr9_arm64,
+ dbg_bcr10_arm64,
+ dbg_bcr11_arm64,
+ dbg_bcr12_arm64,
+ dbg_bcr13_arm64,
+ dbg_bcr14_arm64,
+ dbg_bcr15_arm64,
+ dbg_wvr0_arm64,
+ dbg_wvr1_arm64,
+ dbg_wvr2_arm64,
+ dbg_wvr3_arm64,
+ dbg_wvr4_arm64,
+ dbg_wvr5_arm64,
+ dbg_wvr6_arm64,
+ dbg_wvr7_arm64,
+ dbg_wvr8_arm64,
+ dbg_wvr9_arm64,
+ dbg_wvr10_arm64,
+ dbg_wvr11_arm64,
+ dbg_wvr12_arm64,
+ dbg_wvr13_arm64,
+ dbg_wvr14_arm64,
+ dbg_wvr15_arm64,
+ dbg_wcr0_arm64,
+ dbg_wcr1_arm64,
+ dbg_wcr2_arm64,
+ dbg_wcr3_arm64,
+ dbg_wcr4_arm64,
+ dbg_wcr5_arm64,
+ dbg_wcr6_arm64,
+ dbg_wcr7_arm64,
+ dbg_wcr8_arm64,
+ dbg_wcr9_arm64,
+ dbg_wcr10_arm64,
+ dbg_wcr11_arm64,
+ dbg_wcr12_arm64,
+ dbg_wcr13_arm64,
+ dbg_wcr14_arm64,
+ dbg_wcr15_arm64,
+
+ k_num_registers_arm64,
+ k_num_gpr_registers_arm64 = k_last_gpr_arm64 - k_first_gpr_arm64 + 1,
+ k_num_fpr_registers_arm64 = k_last_fpr_arm64 - k_first_fpr_arm64 + 1
+};
+
+class RegisterContextPOSIX_arm64
+ : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextPOSIX_arm64 (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+ ~RegisterContextPOSIX_arm64();
+
+ void
+ Invalidate();
+
+ void
+ InvalidateAllRegisters();
+
+ size_t
+ GetRegisterCount();
+
+ virtual size_t
+ GetGPRSize();
+
+ virtual unsigned
+ GetRegisterSize(unsigned reg);
+
+ virtual unsigned
+ GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex(size_t reg);
+
+ size_t
+ GetRegisterSetCount();
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t set);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num);
+
+protected:
+ struct RegInfo
+ {
+ uint32_t num_registers;
+ uint32_t num_gpr_registers;
+ uint32_t num_fpr_registers;
+
+ uint32_t last_gpr;
+ uint32_t first_fpr;
+ uint32_t last_fpr;
+
+ uint32_t first_fpr_v;
+ uint32_t last_fpr_v;
+
+ uint32_t gpr_flags;
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct VReg
+ {
+ uint8_t bytes[16];
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct FPU
+ {
+ VReg v[32];
+ uint32_t fpsr;
+ uint32_t fpcr;
+ };
+
+ uint64_t m_gpr_arm64[k_num_gpr_registers_arm64]; // 64-bit general purpose registers.
+ RegInfo m_reg_info;
+ struct RegisterContextPOSIX_arm64::FPU m_fpr; // floating-point registers including extended register sets.
+ std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux)
+
+ // Determines if an extended register set is supported on the processor running the inferior process.
+ virtual bool
+ IsRegisterSetAvailable(size_t set_index);
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ bool
+ IsGPR(unsigned reg);
+
+ bool
+ IsFPR(unsigned reg);
+
+ lldb::ByteOrder GetByteOrder();
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+};
+
+#endif // #ifndef liblldb_RegisterContextPOSIX_arm64_H_
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp
index 45c99aec1657..cefedaec63c1 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp
@@ -20,7 +20,6 @@
#include "lldb/Host/Endian.h"
#include "llvm/Support/Compiler.h"
-#include "ProcessPOSIX.h"
#include "RegisterContextPOSIX_mips64.h"
#include "Plugins/Process/elf-core/ProcessElfCore.h"
@@ -219,7 +218,7 @@ RegisterContextPOSIX_mips64::IsRegisterSetAvailable(size_t set_index)
// Used when parsing DWARF and EH frame information and any other
// object file sections that contain register numbers in them.
uint32_t
-RegisterContextPOSIX_mips64::ConvertRegisterKindToRegisterNumber(uint32_t kind,
+RegisterContextPOSIX_mips64::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
uint32_t num)
{
const uint32_t num_regs = GetRegisterCount();
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
index a2a7d1f45271..991179bdec66 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
@@ -73,7 +73,7 @@ class RegisterContextPOSIX_mips64
public:
RegisterContextPOSIX_mips64 (lldb_private::Thread &thread,
uint32_t concrete_frame_idx,
- RegisterInfoInterface *register_info);
+ lldb_private::RegisterInfoInterface *register_info);
~RegisterContextPOSIX_mips64();
@@ -108,11 +108,11 @@ public:
GetRegisterName(unsigned reg);
uint32_t
- ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num);
+ ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num);
protected:
uint64_t m_gpr_mips64[k_num_gpr_registers_mips64]; // general purpose registers.
- std::unique_ptr<RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux)
+ std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux)
// Determines if an extended register set is supported on the processor running the inferior process.
virtual bool
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
index 9ae541a6309b..2925a33a1690 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
@@ -20,7 +20,6 @@
#include "lldb/Host/Endian.h"
#include "llvm/Support/Compiler.h"
-#include "ProcessPOSIX.h"
#include "RegisterContext_x86.h"
#include "RegisterContextPOSIX_x86.h"
#include "Plugins/Process/elf-core/ProcessElfCore.h"
@@ -62,9 +61,10 @@ g_gpr_regnums_i386[] =
gpr_al_i386,
gpr_bl_i386,
gpr_cl_i386,
- gpr_dl_i386
+ gpr_dl_i386,
+ LLDB_INVALID_REGNUM, // Register sets must be terminated with LLDB_INVALID_REGNUM.
};
-static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) == k_num_gpr_registers_i386,
+static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - 1 == k_num_gpr_registers_i386,
"g_gpr_regnums_i386 has wrong number of register infos");
const uint32_t
@@ -103,9 +103,10 @@ g_fpu_regnums_i386[] =
fpu_xmm4_i386,
fpu_xmm5_i386,
fpu_xmm6_i386,
- fpu_xmm7_i386
+ fpu_xmm7_i386,
+ LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM.
};
-static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) == k_num_fpr_registers_i386,
+static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - 1 == k_num_fpr_registers_i386,
"g_fpu_regnums_i386 has wrong number of register infos");
const uint32_t
@@ -118,9 +119,10 @@ g_avx_regnums_i386[] =
fpu_ymm4_i386,
fpu_ymm5_i386,
fpu_ymm6_i386,
- fpu_ymm7_i386
+ fpu_ymm7_i386,
+ LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM.
};
-static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) == k_num_avx_registers_i386,
+static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - 1 == k_num_avx_registers_i386,
" g_avx_regnums_i386 has wrong number of register infos");
static const
@@ -202,8 +204,9 @@ uint32_t g_gpr_regnums_x86_64[] =
gpr_r13l_x86_64, // Low 8 bits or r13
gpr_r14l_x86_64, // Low 8 bits or r14
gpr_r15l_x86_64, // Low 8 bits or r15
+ LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM.
};
-static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) == k_num_gpr_registers_x86_64,
+static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - 1 == k_num_gpr_registers_x86_64,
"g_gpr_regnums_x86_64 has wrong number of register infos");
static const uint32_t
@@ -250,9 +253,10 @@ g_fpu_regnums_x86_64[] =
fpu_xmm12_x86_64,
fpu_xmm13_x86_64,
fpu_xmm14_x86_64,
- fpu_xmm15_x86_64
+ fpu_xmm15_x86_64,
+ LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM.
};
-static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) == k_num_fpr_registers_x86_64,
+static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - 1 == k_num_fpr_registers_x86_64,
"g_fpu_regnums_x86_64 has wrong number of register infos");
static const uint32_t
@@ -273,9 +277,10 @@ g_avx_regnums_x86_64[] =
fpu_ymm12_x86_64,
fpu_ymm13_x86_64,
fpu_ymm14_x86_64,
- fpu_ymm15_x86_64
+ fpu_ymm15_x86_64,
+ LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM.
};
-static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) == k_num_avx_registers_x86_64,
+static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - 1 == k_num_avx_registers_x86_64,
"g_avx_regnums_x86_64 has wrong number of register infos");
uint32_t RegisterContextPOSIX_x86::g_contained_eax[] = { gpr_eax_i386, LLDB_INVALID_REGNUM };
@@ -384,11 +389,9 @@ RegisterContextPOSIX_x86::RegisterContextPOSIX_x86(Thread &thread,
{
m_register_info_ap.reset(register_info);
- switch (register_info->m_target_arch.GetCore())
+ switch (register_info->m_target_arch.GetMachine())
{
- case ArchSpec::eCore_x86_32_i386:
- case ArchSpec::eCore_x86_32_i486:
- case ArchSpec::eCore_x86_32_i486sx:
+ case llvm::Triple::x86:
m_reg_info.num_registers = k_num_registers_i386;
m_reg_info.num_gpr_registers = k_num_gpr_registers_i386;
m_reg_info.num_fpr_registers = k_num_fpr_registers_i386;
@@ -407,7 +410,7 @@ RegisterContextPOSIX_x86::RegisterContextPOSIX_x86(Thread &thread,
m_reg_info.first_dr = dr0_i386;
m_reg_info.gpr_flags = gpr_eflags_i386;
break;
- case ArchSpec::eCore_x86_64_x86_64:
+ case llvm::Triple::x86_64:
m_reg_info.num_registers = k_num_registers_x86_64;
m_reg_info.num_gpr_registers = k_num_gpr_registers_x86_64;
m_reg_info.num_fpr_registers = k_num_fpr_registers_x86_64;
@@ -537,13 +540,11 @@ RegisterContextPOSIX_x86::GetRegisterSet(size_t set)
{
if (IsRegisterSetAvailable(set))
{
- switch (m_register_info_ap->m_target_arch.GetCore())
+ switch (m_register_info_ap->m_target_arch.GetMachine())
{
- case ArchSpec::eCore_x86_32_i386:
- case ArchSpec::eCore_x86_32_i486:
- case ArchSpec::eCore_x86_32_i486sx:
+ case llvm::Triple::x86:
return &g_reg_sets_i386[set];
- case ArchSpec::eCore_x86_64_x86_64:
+ case llvm::Triple::x86_64:
return &g_reg_sets_x86_64[set];
default:
assert(false && "Unhandled target architecture.");
@@ -647,8 +648,8 @@ RegisterContextPOSIX_x86::IsRegisterSetAvailable(size_t set_index)
// Used when parsing DWARF and EH frame information and any other
// object file sections that contain register numbers in them.
uint32_t
-RegisterContextPOSIX_x86::ConvertRegisterKindToRegisterNumber(uint32_t kind,
- uint32_t num)
+RegisterContextPOSIX_x86::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num)
{
const uint32_t num_regs = GetRegisterCount();
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
index 5e922025b830..4db7802e1b44 100644
--- a/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.h
+++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
@@ -296,7 +296,7 @@ class RegisterContextPOSIX_x86
public:
RegisterContextPOSIX_x86 (lldb_private::Thread &thread,
uint32_t concrete_frame_idx,
- RegisterInfoInterface *register_info);
+ lldb_private::RegisterInfoInterface *register_info);
~RegisterContextPOSIX_x86();
@@ -331,7 +331,7 @@ public:
GetRegisterName(unsigned reg);
uint32_t
- ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num);
+ ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num);
//---------------------------------------------------------------------------
// Note: prefer kernel definitions over user-land
@@ -428,7 +428,7 @@ protected:
FPR m_fpr; // floating-point registers including extended register sets.
IOVEC m_iovec; // wrapper for xsave.
YMM m_ymm_set; // copy of ymmh and xmm register halves.
- std::unique_ptr<RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux)
+ std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux)
// Determines if an extended register set is supported on the processor running the inferior process.
virtual bool
diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
index d35a5d095705..46dafa11d8f7 100644
--- a/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
@@ -167,7 +167,7 @@ RegisterContextThreadMemory::CopyFromRegisterContext (lldb::RegisterContextSP re
}
uint32_t
-RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
{
UpdateRegisterContext ();
if (m_reg_ctx_sp)
diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.h b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
index 8d7a4b622fe8..161ef040e651 100644
--- a/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
+++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
@@ -66,7 +66,7 @@ public:
CopyFromRegisterContext (lldb::RegisterContextSP context);
virtual uint32_t
- ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
//------------------------------------------------------------------
// Subclasses can override these functions if desired
diff --git a/source/Plugins/Process/POSIX/RegisterContext_mips64.h b/source/Plugins/Process/Utility/RegisterContext_mips64.h
index dfd473d7cbec..dfd473d7cbec 100644
--- a/source/Plugins/Process/POSIX/RegisterContext_mips64.h
+++ b/source/Plugins/Process/Utility/RegisterContext_mips64.h
diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86.h b/source/Plugins/Process/Utility/RegisterContext_x86.h
index df3e1e5a84bf..6b3f6fb43e33 100644
--- a/source/Plugins/Process/POSIX/RegisterContext_x86.h
+++ b/source/Plugins/Process/Utility/RegisterContext_x86.h
@@ -34,8 +34,16 @@ enum
gcc_ecx_i386,
gcc_edx_i386,
gcc_ebx_i386,
- gcc_ebp_i386, // Warning: these are switched from dwarf values
- gcc_esp_i386, //
+
+ // on Darwin esp & ebp are reversed in the eh_frame section for i386 (versus dwarf's reg numbering).
+ // To be specific:
+ // i386+darwin eh_frame: 4 is ebp, 5 is esp
+ // i386+everyone else eh_frame: 4 is esp, 5 is ebp
+ // i386 dwarf: 4 is esp, 5 is ebp
+ // lldb will get the darwin-specific eh_frame reg numberings from debugserver instead of here so we
+ // only encode the 4 == esp, 5 == ebp numbers in this generic header.
+ gcc_esp_i386,
+ gcc_ebp_i386,
gcc_esi_i386,
gcc_edi_i386,
gcc_eip_i386,
@@ -411,7 +419,7 @@ struct FXSAVE
uint32_t fiseg; // FPU IP Selector (fcs)
uint32_t fooff; // FPU Operand Pointer Offset (foo)
uint32_t foseg; // FPU Operand Pointer Selector (fos)
- } i386;
+ } i386_;// Added _ in the end to avoid error with gcc defining i386 in some cases
} ptr;
uint32_t mxcsr; // MXCSR Register State
uint32_t mxcsrmask; // MXCSR Mask
diff --git a/source/Plugins/Process/Utility/RegisterInfoInterface.h b/source/Plugins/Process/Utility/RegisterInfoInterface.h
new file mode 100644
index 000000000000..382475f4523a
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterInfoInterface.h
@@ -0,0 +1,49 @@
+//===-- RegisterInfoInterface.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterInfoInterface_h
+#define lldb_RegisterInfoInterface_h
+
+#include "lldb/Core/ArchSpec.h"
+
+namespace lldb_private
+{
+
+ ///------------------------------------------------------------------------------
+ /// @class RegisterInfoInterface
+ ///
+ /// @brief RegisterInfo interface to patch RegisterInfo structure for archs.
+ ///------------------------------------------------------------------------------
+ class RegisterInfoInterface
+ {
+ public:
+ RegisterInfoInterface(const lldb_private::ArchSpec& target_arch) : m_target_arch(target_arch) {}
+ virtual ~RegisterInfoInterface () {}
+
+ virtual size_t
+ GetGPRSize () const = 0;
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo () const = 0;
+
+ virtual uint32_t
+ GetRegisterCount () const = 0;
+
+ const lldb_private::ArchSpec&
+ GetTargetArchitecture() const
+ { return m_target_arch; }
+
+ public:
+ // FIXME make private.
+ lldb_private::ArchSpec m_target_arch;
+ };
+
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/source/Plugins/Process/Utility/RegisterInfos_arm64.h
new file mode 100644
index 000000000000..1bb4e89c8f78
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterInfos_arm64.h
@@ -0,0 +1,347 @@
+//===-- RegisterInfos_arm64.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifdef DECLARE_REGISTER_INFOS_ARM64_STRUCT
+
+#include <stddef.h>
+
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "ARM64_GCC_Registers.h"
+#include "ARM64_DWARF_Registers.h"
+
+#ifndef GPR_OFFSET
+#error GPR_OFFSET must be defined before including this header file
+#endif
+
+#ifndef GPR_OFFSET_NAME
+#error GPR_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef FPU_OFFSET
+#error FPU_OFFSET must be defined before including this header file
+#endif
+
+#ifndef FPU_OFFSET_NAME
+#error FPU_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef EXC_OFFSET_NAME
+#error EXC_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef DBG_OFFSET_NAME
+#error DBG_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef DEFINE_DBG
+#error DEFINE_DBG must be defined before including this header file
+#endif
+
+enum
+{
+ gpr_x0 = 0,
+ gpr_x1,
+ gpr_x2,
+ gpr_x3,
+ gpr_x4,
+ gpr_x5,
+ gpr_x6,
+ gpr_x7,
+ gpr_x8,
+ gpr_x9,
+ gpr_x10,
+ gpr_x11,
+ gpr_x12,
+ gpr_x13,
+ gpr_x14,
+ gpr_x15,
+ gpr_x16,
+ gpr_x17,
+ gpr_x18,
+ gpr_x19,
+ gpr_x20,
+ gpr_x21,
+ gpr_x22,
+ gpr_x23,
+ gpr_x24,
+ gpr_x25,
+ gpr_x26,
+ gpr_x27,
+ gpr_x28,
+ gpr_x29 = 29, gpr_fp = gpr_x29,
+ gpr_x30 = 30, gpr_lr = gpr_x30, gpr_ra = gpr_x30,
+ gpr_x31 = 31, gpr_sp = gpr_x31,
+ gpr_pc = 32,
+ gpr_cpsr,
+
+ fpu_v0,
+ fpu_v1,
+ fpu_v2,
+ fpu_v3,
+ fpu_v4,
+ fpu_v5,
+ fpu_v6,
+ fpu_v7,
+ fpu_v8,
+ fpu_v9,
+ fpu_v10,
+ fpu_v11,
+ fpu_v12,
+ fpu_v13,
+ fpu_v14,
+ fpu_v15,
+ fpu_v16,
+ fpu_v17,
+ fpu_v18,
+ fpu_v19,
+ fpu_v20,
+ fpu_v21,
+ fpu_v22,
+ fpu_v23,
+ fpu_v24,
+ fpu_v25,
+ fpu_v26,
+ fpu_v27,
+ fpu_v28,
+ fpu_v29,
+ fpu_v30,
+ fpu_v31,
+
+ fpu_fpsr,
+ fpu_fpcr,
+
+ exc_far,
+ exc_esr,
+ exc_exception,
+
+ dbg_bvr0,
+ dbg_bvr1,
+ dbg_bvr2,
+ dbg_bvr3,
+ dbg_bvr4,
+ dbg_bvr5,
+ dbg_bvr6,
+ dbg_bvr7,
+ dbg_bvr8,
+ dbg_bvr9,
+ dbg_bvr10,
+ dbg_bvr11,
+ dbg_bvr12,
+ dbg_bvr13,
+ dbg_bvr14,
+ dbg_bvr15,
+
+ dbg_bcr0,
+ dbg_bcr1,
+ dbg_bcr2,
+ dbg_bcr3,
+ dbg_bcr4,
+ dbg_bcr5,
+ dbg_bcr6,
+ dbg_bcr7,
+ dbg_bcr8,
+ dbg_bcr9,
+ dbg_bcr10,
+ dbg_bcr11,
+ dbg_bcr12,
+ dbg_bcr13,
+ dbg_bcr14,
+ dbg_bcr15,
+
+ dbg_wvr0,
+ dbg_wvr1,
+ dbg_wvr2,
+ dbg_wvr3,
+ dbg_wvr4,
+ dbg_wvr5,
+ dbg_wvr6,
+ dbg_wvr7,
+ dbg_wvr8,
+ dbg_wvr9,
+ dbg_wvr10,
+ dbg_wvr11,
+ dbg_wvr12,
+ dbg_wvr13,
+ dbg_wvr14,
+ dbg_wvr15,
+
+ dbg_wcr0,
+ dbg_wcr1,
+ dbg_wcr2,
+ dbg_wcr3,
+ dbg_wcr4,
+ dbg_wcr5,
+ dbg_wcr6,
+ dbg_wcr7,
+ dbg_wcr8,
+ dbg_wcr9,
+ dbg_wcr10,
+ dbg_wcr11,
+ dbg_wcr12,
+ dbg_wcr13,
+ dbg_wcr14,
+ dbg_wcr15,
+
+ k_num_registers
+};
+
+static lldb_private::RegisterInfo g_register_infos_arm64[] = {
+// General purpose registers
+// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== ===============
+{ "x0", NULL, 8, GPR_OFFSET(0), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x0, arm64_dwarf::x0, LLDB_INVALID_REGNUM, arm64_gcc::x0, gpr_x0 }, NULL, NULL},
+{ "x1", NULL, 8, GPR_OFFSET(1), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x1, arm64_dwarf::x1, LLDB_INVALID_REGNUM, arm64_gcc::x1, gpr_x1 }, NULL, NULL},
+{ "x2", NULL, 8, GPR_OFFSET(2), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x2, arm64_dwarf::x2, LLDB_INVALID_REGNUM, arm64_gcc::x2, gpr_x2 }, NULL, NULL},
+{ "x3", NULL, 8, GPR_OFFSET(3), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x3, arm64_dwarf::x3, LLDB_INVALID_REGNUM, arm64_gcc::x3, gpr_x3 }, NULL, NULL},
+{ "x4", NULL, 8, GPR_OFFSET(4), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x4, arm64_dwarf::x4, LLDB_INVALID_REGNUM, arm64_gcc::x4, gpr_x4 }, NULL, NULL},
+{ "x5", NULL, 8, GPR_OFFSET(5), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x5, arm64_dwarf::x5, LLDB_INVALID_REGNUM, arm64_gcc::x5, gpr_x5 }, NULL, NULL},
+{ "x6", NULL, 8, GPR_OFFSET(6), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x6, arm64_dwarf::x6, LLDB_INVALID_REGNUM, arm64_gcc::x6, gpr_x6 }, NULL, NULL},
+{ "x7", NULL, 8, GPR_OFFSET(7), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x7, arm64_dwarf::x7, LLDB_INVALID_REGNUM, arm64_gcc::x7, gpr_x7 }, NULL, NULL},
+{ "x8", NULL, 8, GPR_OFFSET(8), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x8, arm64_dwarf::x8, LLDB_INVALID_REGNUM, arm64_gcc::x8, gpr_x8 }, NULL, NULL},
+{ "x9", NULL, 8, GPR_OFFSET(9), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x9, arm64_dwarf::x9, LLDB_INVALID_REGNUM, arm64_gcc::x9, gpr_x9 }, NULL, NULL},
+{ "x10", NULL, 8, GPR_OFFSET(10), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x10, arm64_dwarf::x10, LLDB_INVALID_REGNUM, arm64_gcc::x10, gpr_x10 }, NULL, NULL},
+{ "x11", NULL, 8, GPR_OFFSET(11), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x11, arm64_dwarf::x11, LLDB_INVALID_REGNUM, arm64_gcc::x11, gpr_x11 }, NULL, NULL},
+{ "x12", NULL, 8, GPR_OFFSET(12), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x12, arm64_dwarf::x12, LLDB_INVALID_REGNUM, arm64_gcc::x12, gpr_x12 }, NULL, NULL},
+{ "x13", NULL, 8, GPR_OFFSET(13), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x13, arm64_dwarf::x13, LLDB_INVALID_REGNUM, arm64_gcc::x13, gpr_x13 }, NULL, NULL},
+{ "x14", NULL, 8, GPR_OFFSET(14), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x14, arm64_dwarf::x14, LLDB_INVALID_REGNUM, arm64_gcc::x14, gpr_x14 }, NULL, NULL},
+{ "x15", NULL, 8, GPR_OFFSET(15), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x15, arm64_dwarf::x15, LLDB_INVALID_REGNUM, arm64_gcc::x15, gpr_x15 }, NULL, NULL},
+{ "x16", NULL, 8, GPR_OFFSET(16), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x16, arm64_dwarf::x16, LLDB_INVALID_REGNUM, arm64_gcc::x16, gpr_x16 }, NULL, NULL},
+{ "x17", NULL, 8, GPR_OFFSET(17), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x17, arm64_dwarf::x17, LLDB_INVALID_REGNUM, arm64_gcc::x17, gpr_x17 }, NULL, NULL},
+{ "x18", NULL, 8, GPR_OFFSET(18), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x18, arm64_dwarf::x18, LLDB_INVALID_REGNUM, arm64_gcc::x18, gpr_x18 }, NULL, NULL},
+{ "x19", NULL, 8, GPR_OFFSET(19), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x19, arm64_dwarf::x19, LLDB_INVALID_REGNUM, arm64_gcc::x19, gpr_x19 }, NULL, NULL},
+{ "x20", NULL, 8, GPR_OFFSET(20), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x20, arm64_dwarf::x20, LLDB_INVALID_REGNUM, arm64_gcc::x20, gpr_x20 }, NULL, NULL},
+{ "x21", NULL, 8, GPR_OFFSET(21), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x21, arm64_dwarf::x21, LLDB_INVALID_REGNUM, arm64_gcc::x21, gpr_x21 }, NULL, NULL},
+{ "x22", NULL, 8, GPR_OFFSET(22), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x22, arm64_dwarf::x22, LLDB_INVALID_REGNUM, arm64_gcc::x22, gpr_x22 }, NULL, NULL},
+{ "x23", NULL, 8, GPR_OFFSET(23), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x23, arm64_dwarf::x23, LLDB_INVALID_REGNUM, arm64_gcc::x23, gpr_x23 }, NULL, NULL},
+{ "x24", NULL, 8, GPR_OFFSET(24), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x24, arm64_dwarf::x24, LLDB_INVALID_REGNUM, arm64_gcc::x24, gpr_x24 }, NULL, NULL},
+{ "x25", NULL, 8, GPR_OFFSET(25), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x25, arm64_dwarf::x25, LLDB_INVALID_REGNUM, arm64_gcc::x25, gpr_x25 }, NULL, NULL},
+{ "x26", NULL, 8, GPR_OFFSET(26), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x26, arm64_dwarf::x26, LLDB_INVALID_REGNUM, arm64_gcc::x26, gpr_x26 }, NULL, NULL},
+{ "x27", NULL, 8, GPR_OFFSET(27), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x27, arm64_dwarf::x27, LLDB_INVALID_REGNUM, arm64_gcc::x27, gpr_x27 }, NULL, NULL},
+{ "x28", NULL, 8, GPR_OFFSET(28), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x28, arm64_dwarf::x28, LLDB_INVALID_REGNUM, arm64_gcc::x28, gpr_x28 }, NULL, NULL},
+
+{ "fp", "x29", 8, GPR_OFFSET(29), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::fp, arm64_dwarf::fp, LLDB_REGNUM_GENERIC_FP, arm64_gcc::fp, gpr_fp }, NULL, NULL},
+{ "lr", "x30", 8, GPR_OFFSET(30), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::lr, arm64_dwarf::lr, LLDB_REGNUM_GENERIC_RA, arm64_gcc::lr, gpr_lr }, NULL, NULL},
+{ "sp", "x31", 8, GPR_OFFSET(31), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::sp, arm64_dwarf::sp, LLDB_REGNUM_GENERIC_SP, arm64_gcc::sp, gpr_sp }, NULL, NULL},
+{ "pc", NULL, 8, GPR_OFFSET(32), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::pc, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, arm64_gcc::pc, gpr_pc }, NULL, NULL},
+
+{ "cpsr", NULL, 4, GPR_OFFSET_NAME(cpsr), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::cpsr, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, arm64_gcc::cpsr, gpr_cpsr }, NULL, NULL},
+
+{ "v0", NULL, 16, FPU_OFFSET(0), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v0, LLDB_INVALID_REGNUM, arm64_gcc::v0, fpu_v0 }, NULL, NULL},
+{ "v1", NULL, 16, FPU_OFFSET(1), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v1, LLDB_INVALID_REGNUM, arm64_gcc::v1, fpu_v1 }, NULL, NULL},
+{ "v2", NULL, 16, FPU_OFFSET(2), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v2, LLDB_INVALID_REGNUM, arm64_gcc::v2, fpu_v2 }, NULL, NULL},
+{ "v3", NULL, 16, FPU_OFFSET(3), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v3, LLDB_INVALID_REGNUM, arm64_gcc::v3, fpu_v3 }, NULL, NULL},
+{ "v4", NULL, 16, FPU_OFFSET(4), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v4, LLDB_INVALID_REGNUM, arm64_gcc::v4, fpu_v4 }, NULL, NULL},
+{ "v5", NULL, 16, FPU_OFFSET(5), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v5, LLDB_INVALID_REGNUM, arm64_gcc::v5, fpu_v5 }, NULL, NULL},
+{ "v6", NULL, 16, FPU_OFFSET(6), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v6, LLDB_INVALID_REGNUM, arm64_gcc::v6, fpu_v6 }, NULL, NULL},
+{ "v7", NULL, 16, FPU_OFFSET(7), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v7, LLDB_INVALID_REGNUM, arm64_gcc::v7, fpu_v7 }, NULL, NULL},
+{ "v8", NULL, 16, FPU_OFFSET(8), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v8, LLDB_INVALID_REGNUM, arm64_gcc::v8, fpu_v8 }, NULL, NULL},
+{ "v9", NULL, 16, FPU_OFFSET(9), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v9, LLDB_INVALID_REGNUM, arm64_gcc::v9, fpu_v9 }, NULL, NULL},
+{ "v10", NULL, 16, FPU_OFFSET(10), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v10, LLDB_INVALID_REGNUM, arm64_gcc::v10, fpu_v10 }, NULL, NULL},
+{ "v11", NULL, 16, FPU_OFFSET(11), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v11, LLDB_INVALID_REGNUM, arm64_gcc::v11, fpu_v11 }, NULL, NULL},
+{ "v12", NULL, 16, FPU_OFFSET(12), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v12, LLDB_INVALID_REGNUM, arm64_gcc::v12, fpu_v12 }, NULL, NULL},
+{ "v13", NULL, 16, FPU_OFFSET(13), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v13, LLDB_INVALID_REGNUM, arm64_gcc::v13, fpu_v13 }, NULL, NULL},
+{ "v14", NULL, 16, FPU_OFFSET(14), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v14, LLDB_INVALID_REGNUM, arm64_gcc::v14, fpu_v14 }, NULL, NULL},
+{ "v15", NULL, 16, FPU_OFFSET(15), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v15, LLDB_INVALID_REGNUM, arm64_gcc::v15, fpu_v15 }, NULL, NULL},
+{ "v16", NULL, 16, FPU_OFFSET(16), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v16, LLDB_INVALID_REGNUM, arm64_gcc::v16, fpu_v16 }, NULL, NULL},
+{ "v17", NULL, 16, FPU_OFFSET(17), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v17, LLDB_INVALID_REGNUM, arm64_gcc::v17, fpu_v17 }, NULL, NULL},
+{ "v18", NULL, 16, FPU_OFFSET(18), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v18, LLDB_INVALID_REGNUM, arm64_gcc::v18, fpu_v18 }, NULL, NULL},
+{ "v19", NULL, 16, FPU_OFFSET(19), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v19, LLDB_INVALID_REGNUM, arm64_gcc::v19, fpu_v19 }, NULL, NULL},
+{ "v20", NULL, 16, FPU_OFFSET(20), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v20, LLDB_INVALID_REGNUM, arm64_gcc::v20, fpu_v20 }, NULL, NULL},
+{ "v21", NULL, 16, FPU_OFFSET(21), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v21, LLDB_INVALID_REGNUM, arm64_gcc::v21, fpu_v21 }, NULL, NULL},
+{ "v22", NULL, 16, FPU_OFFSET(22), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v22, LLDB_INVALID_REGNUM, arm64_gcc::v22, fpu_v22 }, NULL, NULL},
+{ "v23", NULL, 16, FPU_OFFSET(23), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v23, LLDB_INVALID_REGNUM, arm64_gcc::v23, fpu_v23 }, NULL, NULL},
+{ "v24", NULL, 16, FPU_OFFSET(24), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v24, LLDB_INVALID_REGNUM, arm64_gcc::v24, fpu_v24 }, NULL, NULL},
+{ "v25", NULL, 16, FPU_OFFSET(25), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v25, LLDB_INVALID_REGNUM, arm64_gcc::v25, fpu_v25 }, NULL, NULL},
+{ "v26", NULL, 16, FPU_OFFSET(26), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v26, LLDB_INVALID_REGNUM, arm64_gcc::v26, fpu_v26 }, NULL, NULL},
+{ "v27", NULL, 16, FPU_OFFSET(27), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v27, LLDB_INVALID_REGNUM, arm64_gcc::v27, fpu_v27 }, NULL, NULL},
+{ "v28", NULL, 16, FPU_OFFSET(28), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v28, LLDB_INVALID_REGNUM, arm64_gcc::v28, fpu_v28 }, NULL, NULL},
+{ "v29", NULL, 16, FPU_OFFSET(29), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v29, LLDB_INVALID_REGNUM, arm64_gcc::v29, fpu_v29 }, NULL, NULL},
+{ "v30", NULL, 16, FPU_OFFSET(30), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v30, LLDB_INVALID_REGNUM, arm64_gcc::v30, fpu_v30 }, NULL, NULL},
+{ "v31", NULL, 16, FPU_OFFSET(31), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v31, LLDB_INVALID_REGNUM, arm64_gcc::v31, fpu_v31 }, NULL, NULL},
+
+{ "fpsr", NULL, 4, FPU_OFFSET_NAME(fpsr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpsr }, NULL, NULL},
+{ "fpcr", NULL, 4, FPU_OFFSET_NAME(fpcr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpcr }, NULL, NULL},
+
+{ "far", NULL, 8, EXC_OFFSET_NAME(far), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, NULL, NULL},
+{ "esr", NULL, 4, EXC_OFFSET_NAME(esr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_esr }, NULL, NULL},
+{ "exception",NULL, 4, EXC_OFFSET_NAME(exception), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL},
+
+{ DEFINE_DBG (bvr, 0) },
+{ DEFINE_DBG (bvr, 1) },
+{ DEFINE_DBG (bvr, 2) },
+{ DEFINE_DBG (bvr, 3) },
+{ DEFINE_DBG (bvr, 4) },
+{ DEFINE_DBG (bvr, 5) },
+{ DEFINE_DBG (bvr, 6) },
+{ DEFINE_DBG (bvr, 7) },
+{ DEFINE_DBG (bvr, 8) },
+{ DEFINE_DBG (bvr, 9) },
+{ DEFINE_DBG (bvr, 10) },
+{ DEFINE_DBG (bvr, 11) },
+{ DEFINE_DBG (bvr, 12) },
+{ DEFINE_DBG (bvr, 13) },
+{ DEFINE_DBG (bvr, 14) },
+{ DEFINE_DBG (bvr, 15) },
+
+{ DEFINE_DBG (bcr, 0) },
+{ DEFINE_DBG (bcr, 1) },
+{ DEFINE_DBG (bcr, 2) },
+{ DEFINE_DBG (bcr, 3) },
+{ DEFINE_DBG (bcr, 4) },
+{ DEFINE_DBG (bcr, 5) },
+{ DEFINE_DBG (bcr, 6) },
+{ DEFINE_DBG (bcr, 7) },
+{ DEFINE_DBG (bcr, 8) },
+{ DEFINE_DBG (bcr, 9) },
+{ DEFINE_DBG (bcr, 10) },
+{ DEFINE_DBG (bcr, 11) },
+{ DEFINE_DBG (bcr, 12) },
+{ DEFINE_DBG (bcr, 13) },
+{ DEFINE_DBG (bcr, 14) },
+{ DEFINE_DBG (bcr, 15) },
+
+{ DEFINE_DBG (wvr, 0) },
+{ DEFINE_DBG (wvr, 1) },
+{ DEFINE_DBG (wvr, 2) },
+{ DEFINE_DBG (wvr, 3) },
+{ DEFINE_DBG (wvr, 4) },
+{ DEFINE_DBG (wvr, 5) },
+{ DEFINE_DBG (wvr, 6) },
+{ DEFINE_DBG (wvr, 7) },
+{ DEFINE_DBG (wvr, 8) },
+{ DEFINE_DBG (wvr, 9) },
+{ DEFINE_DBG (wvr, 10) },
+{ DEFINE_DBG (wvr, 11) },
+{ DEFINE_DBG (wvr, 12) },
+{ DEFINE_DBG (wvr, 13) },
+{ DEFINE_DBG (wvr, 14) },
+{ DEFINE_DBG (wvr, 15) },
+
+{ DEFINE_DBG (wcr, 0) },
+{ DEFINE_DBG (wcr, 1) },
+{ DEFINE_DBG (wcr, 2) },
+{ DEFINE_DBG (wcr, 3) },
+{ DEFINE_DBG (wcr, 4) },
+{ DEFINE_DBG (wcr, 5) },
+{ DEFINE_DBG (wcr, 6) },
+{ DEFINE_DBG (wcr, 7) },
+{ DEFINE_DBG (wcr, 8) },
+{ DEFINE_DBG (wcr, 9) },
+{ DEFINE_DBG (wcr, 10) },
+{ DEFINE_DBG (wcr, 11) },
+{ DEFINE_DBG (wcr, 12) },
+{ DEFINE_DBG (wcr, 13) },
+{ DEFINE_DBG (wcr, 14) },
+{ DEFINE_DBG (wcr, 15) }
+};
+
+#endif // DECLARE_REGISTER_INFOS_ARM64_STRUCT
diff --git a/source/Plugins/Process/POSIX/RegisterInfos_i386.h b/source/Plugins/Process/Utility/RegisterInfos_i386.h
index 7c516568cd62..fa152b4147ce 100644
--- a/source/Plugins/Process/POSIX/RegisterInfos_i386.h
+++ b/source/Plugins/Process/Utility/RegisterInfos_i386.h
@@ -8,6 +8,8 @@
//===---------------------------------------------------------------------===//
#include "llvm/Support/Compiler.h"
+#include <stddef.h>
+
#ifdef DECLARE_REGISTER_INFOS_I386_STRUCT
// Computes the offset of the given GPR in the user data area.
@@ -24,7 +26,9 @@
(LLVM_EXTENSION offsetof(YMM, regname))
// Number of bytes needed to represent a FPR.
+#if !defined(FPR_SIZE)
#define FPR_SIZE(reg) sizeof(((FXSAVE*)NULL)->reg)
+#endif
// Number of bytes needed to represent the i'th FP register.
#define FP_SIZE sizeof(((MMSReg*)NULL)->bytes)
@@ -37,7 +41,7 @@
// Note that the size and offset will be updated by platform-specific classes.
#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
- { #reg, alt, sizeof(GPR::reg), GPR_OFFSET(reg), eEncodingUint, \
+ { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \
eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_i386 }, NULL, NULL }
#define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \
@@ -129,10 +133,10 @@ g_register_infos_i386[] =
DEFINE_FPR(fstat, fstat, LLDB_INVALID_REGNUM, dwarf_fstat_i386, LLDB_INVALID_REGNUM, gdb_fstat_i386),
DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftag_i386),
DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop_i386),
- DEFINE_FPR(fiseg, ptr.i386.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_i386),
- DEFINE_FPR(fioff, ptr.i386.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_i386),
- DEFINE_FPR(foseg, ptr.i386.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_i386),
- DEFINE_FPR(fooff, ptr.i386.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_i386),
+ DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_i386),
+ DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_i386),
+ DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_i386),
+ DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_i386),
DEFINE_FPR(mxcsr, mxcsr, LLDB_INVALID_REGNUM, dwarf_mxcsr_i386, LLDB_INVALID_REGNUM, gdb_mxcsr_i386),
DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
diff --git a/source/Plugins/Process/POSIX/RegisterInfos_mips64.h b/source/Plugins/Process/Utility/RegisterInfos_mips64.h
index 13526e3680b7..187b8e98332e 100644
--- a/source/Plugins/Process/POSIX/RegisterInfos_mips64.h
+++ b/source/Plugins/Process/Utility/RegisterInfos_mips64.h
@@ -7,6 +7,8 @@
//
//===---------------------------------------------------------------------===//
+#include <stddef.h>
+
// Computes the offset of the given GPR in the user data area.
#define GPR_OFFSET(regname) \
(offsetof(GPR, regname))
@@ -15,7 +17,7 @@
// Note that the size and offset will be updated by platform-specific classes.
#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
- { #reg, alt, sizeof(GPR::reg), GPR_OFFSET(reg), eEncodingUint, \
+ { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \
eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL }
static RegisterInfo
diff --git a/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h b/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
index 86abdba68db6..c4dc6041ce43 100644
--- a/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h
+++ b/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
@@ -8,6 +8,8 @@
//===---------------------------------------------------------------------===//
#include "llvm/Support/Compiler.h"
+#include <stddef.h>
+
// Computes the offset of the given GPR in the user data area.
#define GPR_OFFSET(regname) \
(LLVM_EXTENSION offsetof(GPR, regname))
@@ -39,7 +41,7 @@
// Note that the size and offset will be updated by platform-specific classes.
#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
- { #reg, alt, sizeof(GPR::reg), GPR_OFFSET(reg), eEncodingUint, \
+ { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \
eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_x86_64 }, NULL, NULL }
#define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \
@@ -175,10 +177,10 @@ g_register_infos_x86_64[] =
DEFINE_FPR(fstat, fstat, gcc_dwarf_fstat_x86_64, gcc_dwarf_fstat_x86_64, LLDB_INVALID_REGNUM, gdb_fstat_x86_64),
DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftag_x86_64),
DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop_x86_64),
- DEFINE_FPR(fiseg, ptr.i386.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_x86_64),
- DEFINE_FPR(fioff, ptr.i386.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_x86_64),
- DEFINE_FPR(foseg, ptr.i386.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_x86_64),
- DEFINE_FPR(fooff, ptr.i386.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_x86_64),
+ DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_x86_64),
+ DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_x86_64),
+ DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_x86_64),
+ DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_x86_64),
DEFINE_FPR(mxcsr, mxcsr, gcc_dwarf_mxcsr_x86_64, gcc_dwarf_mxcsr_x86_64, LLDB_INVALID_REGNUM, gdb_mxcsr_x86_64),
DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
@@ -343,10 +345,10 @@ do {
UPDATE_FPR_INFO(fstat, fstat);
UPDATE_FPR_INFO(ftag, ftag);
UPDATE_FPR_INFO(fop, fop);
- UPDATE_FPR_INFO(fiseg, ptr.i386.fiseg);
- UPDATE_FPR_INFO(fioff, ptr.i386.fioff);
- UPDATE_FPR_INFO(fooff, ptr.i386.fooff);
- UPDATE_FPR_INFO(foseg, ptr.i386.foseg);
+ UPDATE_FPR_INFO(fiseg, ptr.i386_.fiseg);
+ UPDATE_FPR_INFO(fioff, ptr.i386_.fioff);
+ UPDATE_FPR_INFO(fooff, ptr.i386_.fooff);
+ UPDATE_FPR_INFO(foseg, ptr.i386_.foseg);
UPDATE_FPR_INFO(mxcsr, mxcsr);
UPDATE_FPR_INFO(mxcsrmask, mxcsrmask);
diff --git a/source/Plugins/Process/Utility/StopInfoMachException.cpp b/source/Plugins/Process/Utility/StopInfoMachException.cpp
index 51d2052e1931..0e3e559aef5c 100644
--- a/source/Plugins/Process/Utility/StopInfoMachException.cpp
+++ b/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -363,20 +363,30 @@ StopInfoMachException::CreateStopReasonWithMachException
if (exc_code == 1) // EXC_I386_SGL
{
if (!exc_sub_code)
- return StopInfo::CreateStopReasonToTrace(thread);
-
- // It's a watchpoint, then.
- // The exc_sub_code indicates the data break address.
- lldb::WatchpointSP wp_sp;
- if (target)
- wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
- if (wp_sp && wp_sp->IsEnabled())
{
- // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data.
- // Set the hardware index if that's the case.
- if (exc_data_count >=3)
- wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
- return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
+ // This looks like a plain trap.
+ // Have to check if there is a breakpoint here as well. When you single-step onto a trap,
+ // the single step stops you not to trap. Since we also do that check below, let's just use
+ // that logic.
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ else
+ {
+
+ // It's a watchpoint, then.
+ // The exc_sub_code indicates the data break address.
+ lldb::WatchpointSP wp_sp;
+ if (target)
+ wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
+ if (wp_sp && wp_sp->IsEnabled())
+ {
+ // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data.
+ // Set the hardware index if that's the case.
+ if (exc_data_count >=3)
+ wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
+ return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
+ }
}
}
else if (exc_code == 2 || // EXC_I386_BPT
@@ -429,6 +439,38 @@ StopInfoMachException::CreateStopReasonWithMachException
}
break;
+ case llvm::Triple::aarch64:
+ {
+ if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT
+ {
+ // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0 is set
+ return StopInfo::CreateStopReasonToTrace(thread);
+ }
+ if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
+ {
+ // It's a watchpoint, then, if the exc_sub_code indicates a known/enabled
+ // data break address from our watchpoint list.
+ lldb::WatchpointSP wp_sp;
+ if (target)
+ wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
+ if (wp_sp && wp_sp->IsEnabled())
+ {
+ // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data.
+ // Set the hardware index if that's the case.
+ if (exc_data_count >= 3)
+ wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
+ return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
+ }
+ // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS
+ if (thread.GetTemporaryResumeState() == eStateStepping)
+ return StopInfo::CreateStopReasonToTrace(thread);
+ }
+ // It looks like exc_sub_code has the 4 bytes of the instruction that triggered the
+ // exception, i.e. our breakpoint opcode
+ is_actual_breakpoint = exc_code == 1;
+ break;
+ }
+
default:
break;
}
diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp
index 5db08e5c26de..37fd4f489552 100644
--- a/source/Plugins/Process/Utility/UnwindLLDB.cpp
+++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp
@@ -347,7 +347,7 @@ bool
UnwindLLDB::SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc, uint32_t starting_frame_num, bool pc_reg)
{
int64_t frame_num = starting_frame_num;
- if (frame_num >= m_frames.size())
+ if (static_cast<size_t>(frame_num) >= m_frames.size())
return false;
// Never interrogate more than one level while looking for the saved pc value. If the value
diff --git a/source/Plugins/Process/Utility/lldb-x86-register-enums.h b/source/Plugins/Process/Utility/lldb-x86-register-enums.h
new file mode 100644
index 000000000000..c4706d567b70
--- /dev/null
+++ b/source/Plugins/Process/Utility/lldb-x86-register-enums.h
@@ -0,0 +1,292 @@
+//===-- lldb-x86-register-enums.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_x86_register_enums_h
+#define lldb_x86_register_enums_h
+
+namespace lldb_private
+{
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all i386 registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_i386,
+ gpr_eax_i386 = k_first_gpr_i386,
+ gpr_ebx_i386,
+ gpr_ecx_i386,
+ gpr_edx_i386,
+ gpr_edi_i386,
+ gpr_esi_i386,
+ gpr_ebp_i386,
+ gpr_esp_i386,
+ gpr_eip_i386,
+ gpr_eflags_i386,
+ gpr_cs_i386,
+ gpr_fs_i386,
+ gpr_gs_i386,
+ gpr_ss_i386,
+ gpr_ds_i386,
+ gpr_es_i386,
+
+ k_first_alias_i386,
+ gpr_ax_i386 = k_first_alias_i386,
+ gpr_bx_i386,
+ gpr_cx_i386,
+ gpr_dx_i386,
+ gpr_di_i386,
+ gpr_si_i386,
+ gpr_bp_i386,
+ gpr_sp_i386,
+ gpr_ah_i386,
+ gpr_bh_i386,
+ gpr_ch_i386,
+ gpr_dh_i386,
+ gpr_al_i386,
+ gpr_bl_i386,
+ gpr_cl_i386,
+ gpr_dl_i386,
+ k_last_alias_i386 = gpr_dl_i386,
+
+ k_last_gpr_i386 = k_last_alias_i386,
+
+ k_first_fpr_i386,
+ fpu_fctrl_i386 = k_first_fpr_i386,
+ fpu_fstat_i386,
+ fpu_ftag_i386,
+ fpu_fop_i386,
+ fpu_fiseg_i386,
+ fpu_fioff_i386,
+ fpu_foseg_i386,
+ fpu_fooff_i386,
+ fpu_mxcsr_i386,
+ fpu_mxcsrmask_i386,
+ fpu_st0_i386,
+ fpu_st1_i386,
+ fpu_st2_i386,
+ fpu_st3_i386,
+ fpu_st4_i386,
+ fpu_st5_i386,
+ fpu_st6_i386,
+ fpu_st7_i386,
+ fpu_mm0_i386,
+ fpu_mm1_i386,
+ fpu_mm2_i386,
+ fpu_mm3_i386,
+ fpu_mm4_i386,
+ fpu_mm5_i386,
+ fpu_mm6_i386,
+ fpu_mm7_i386,
+ fpu_xmm0_i386,
+ fpu_xmm1_i386,
+ fpu_xmm2_i386,
+ fpu_xmm3_i386,
+ fpu_xmm4_i386,
+ fpu_xmm5_i386,
+ fpu_xmm6_i386,
+ fpu_xmm7_i386,
+ k_last_fpr_i386 = fpu_xmm7_i386,
+
+ k_first_avx_i386,
+ fpu_ymm0_i386 = k_first_avx_i386,
+ fpu_ymm1_i386,
+ fpu_ymm2_i386,
+ fpu_ymm3_i386,
+ fpu_ymm4_i386,
+ fpu_ymm5_i386,
+ fpu_ymm6_i386,
+ fpu_ymm7_i386,
+ k_last_avx_i386 = fpu_ymm7_i386,
+
+ dr0_i386,
+ dr1_i386,
+ dr2_i386,
+ dr3_i386,
+ dr4_i386,
+ dr5_i386,
+ dr6_i386,
+ dr7_i386,
+
+ k_num_registers_i386,
+ k_num_gpr_registers_i386 = k_last_gpr_i386 - k_first_gpr_i386 + 1,
+ k_num_fpr_registers_i386 = k_last_fpr_i386 - k_first_fpr_i386 + 1,
+ k_num_avx_registers_i386 = k_last_avx_i386 - k_first_avx_i386 + 1
+ };
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all x86_64 registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_x86_64,
+ gpr_rax_x86_64 = k_first_gpr_x86_64,
+ gpr_rbx_x86_64,
+ gpr_rcx_x86_64,
+ gpr_rdx_x86_64,
+ gpr_rdi_x86_64,
+ gpr_rsi_x86_64,
+ gpr_rbp_x86_64,
+ gpr_rsp_x86_64,
+ gpr_r8_x86_64,
+ gpr_r9_x86_64,
+ gpr_r10_x86_64,
+ gpr_r11_x86_64,
+ gpr_r12_x86_64,
+ gpr_r13_x86_64,
+ gpr_r14_x86_64,
+ gpr_r15_x86_64,
+ gpr_rip_x86_64,
+ gpr_rflags_x86_64,
+ gpr_cs_x86_64,
+ gpr_fs_x86_64,
+ gpr_gs_x86_64,
+ gpr_ss_x86_64,
+ gpr_ds_x86_64,
+ gpr_es_x86_64,
+
+ k_first_alias_x86_64,
+ gpr_eax_x86_64 = k_first_alias_x86_64,
+ gpr_ebx_x86_64,
+ gpr_ecx_x86_64,
+ gpr_edx_x86_64,
+ gpr_edi_x86_64,
+ gpr_esi_x86_64,
+ gpr_ebp_x86_64,
+ gpr_esp_x86_64,
+ gpr_r8d_x86_64, // Low 32 bits of r8
+ gpr_r9d_x86_64, // Low 32 bits of r9
+ gpr_r10d_x86_64, // Low 32 bits of r10
+ gpr_r11d_x86_64, // Low 32 bits of r11
+ gpr_r12d_x86_64, // Low 32 bits of r12
+ gpr_r13d_x86_64, // Low 32 bits of r13
+ gpr_r14d_x86_64, // Low 32 bits of r14
+ gpr_r15d_x86_64, // Low 32 bits of r15
+ gpr_ax_x86_64,
+ gpr_bx_x86_64,
+ gpr_cx_x86_64,
+ gpr_dx_x86_64,
+ gpr_di_x86_64,
+ gpr_si_x86_64,
+ gpr_bp_x86_64,
+ gpr_sp_x86_64,
+ gpr_r8w_x86_64, // Low 16 bits of r8
+ gpr_r9w_x86_64, // Low 16 bits of r9
+ gpr_r10w_x86_64, // Low 16 bits of r10
+ gpr_r11w_x86_64, // Low 16 bits of r11
+ gpr_r12w_x86_64, // Low 16 bits of r12
+ gpr_r13w_x86_64, // Low 16 bits of r13
+ gpr_r14w_x86_64, // Low 16 bits of r14
+ gpr_r15w_x86_64, // Low 16 bits of r15
+ gpr_ah_x86_64,
+ gpr_bh_x86_64,
+ gpr_ch_x86_64,
+ gpr_dh_x86_64,
+ gpr_al_x86_64,
+ gpr_bl_x86_64,
+ gpr_cl_x86_64,
+ gpr_dl_x86_64,
+ gpr_dil_x86_64,
+ gpr_sil_x86_64,
+ gpr_bpl_x86_64,
+ gpr_spl_x86_64,
+ gpr_r8l_x86_64, // Low 8 bits of r8
+ gpr_r9l_x86_64, // Low 8 bits of r9
+ gpr_r10l_x86_64, // Low 8 bits of r10
+ gpr_r11l_x86_64, // Low 8 bits of r11
+ gpr_r12l_x86_64, // Low 8 bits of r12
+ gpr_r13l_x86_64, // Low 8 bits of r13
+ gpr_r14l_x86_64, // Low 8 bits of r14
+ gpr_r15l_x86_64, // Low 8 bits of r15
+ k_last_alias_x86_64 = gpr_r15l_x86_64,
+
+ k_last_gpr_x86_64 = k_last_alias_x86_64,
+
+ k_first_fpr_x86_64,
+ fpu_fctrl_x86_64 = k_first_fpr_x86_64,
+ fpu_fstat_x86_64,
+ fpu_ftag_x86_64,
+ fpu_fop_x86_64,
+ fpu_fiseg_x86_64,
+ fpu_fioff_x86_64,
+ fpu_foseg_x86_64,
+ fpu_fooff_x86_64,
+ fpu_mxcsr_x86_64,
+ fpu_mxcsrmask_x86_64,
+ fpu_st0_x86_64,
+ fpu_st1_x86_64,
+ fpu_st2_x86_64,
+ fpu_st3_x86_64,
+ fpu_st4_x86_64,
+ fpu_st5_x86_64,
+ fpu_st6_x86_64,
+ fpu_st7_x86_64,
+ fpu_mm0_x86_64,
+ fpu_mm1_x86_64,
+ fpu_mm2_x86_64,
+ fpu_mm3_x86_64,
+ fpu_mm4_x86_64,
+ fpu_mm5_x86_64,
+ fpu_mm6_x86_64,
+ fpu_mm7_x86_64,
+ fpu_xmm0_x86_64,
+ fpu_xmm1_x86_64,
+ fpu_xmm2_x86_64,
+ fpu_xmm3_x86_64,
+ fpu_xmm4_x86_64,
+ fpu_xmm5_x86_64,
+ fpu_xmm6_x86_64,
+ fpu_xmm7_x86_64,
+ fpu_xmm8_x86_64,
+ fpu_xmm9_x86_64,
+ fpu_xmm10_x86_64,
+ fpu_xmm11_x86_64,
+ fpu_xmm12_x86_64,
+ fpu_xmm13_x86_64,
+ fpu_xmm14_x86_64,
+ fpu_xmm15_x86_64,
+ k_last_fpr_x86_64 = fpu_xmm15_x86_64,
+
+ k_first_avx_x86_64,
+ fpu_ymm0_x86_64 = k_first_avx_x86_64,
+ fpu_ymm1_x86_64,
+ fpu_ymm2_x86_64,
+ fpu_ymm3_x86_64,
+ fpu_ymm4_x86_64,
+ fpu_ymm5_x86_64,
+ fpu_ymm6_x86_64,
+ fpu_ymm7_x86_64,
+ fpu_ymm8_x86_64,
+ fpu_ymm9_x86_64,
+ fpu_ymm10_x86_64,
+ fpu_ymm11_x86_64,
+ fpu_ymm12_x86_64,
+ fpu_ymm13_x86_64,
+ fpu_ymm14_x86_64,
+ fpu_ymm15_x86_64,
+ k_last_avx_x86_64 = fpu_ymm15_x86_64,
+
+ dr0_x86_64,
+ dr1_x86_64,
+ dr2_x86_64,
+ dr3_x86_64,
+ dr4_x86_64,
+ dr5_x86_64,
+ dr6_x86_64,
+ dr7_x86_64,
+
+ k_num_registers_x86_64,
+ k_num_gpr_registers_x86_64 = k_last_gpr_x86_64 - k_first_gpr_x86_64 + 1,
+ k_num_fpr_registers_x86_64 = k_last_fpr_x86_64 - k_first_fpr_x86_64 + 1,
+ k_num_avx_registers_x86_64 = k_last_avx_x86_64 - k_first_avx_x86_64 + 1
+ };
+
+}
+
+#endif // #ifndef lldb_x86_register_enums_h
diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index 7ea5c89e7df4..566816783c7e 100644
--- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -17,12 +17,17 @@
#include "lldb/Core/Section.h"
#include "lldb/Core/State.h"
#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/DynamicLoader.h"
-#include "ProcessPOSIXLog.h"
+#include "lldb/Target/UnixSignals.h"
+
+#include "llvm/Support/ELF.h"
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
+#include "Plugins/Process/Utility/FreeBSDSignals.h"
+#include "Plugins/Process/Utility/LinuxSignals.h"
// Project includes
#include "ProcessElfCore.h"
@@ -54,8 +59,25 @@ lldb::ProcessSP
ProcessElfCore::CreateInstance (Target &target, Listener &listener, const FileSpec *crash_file)
{
lldb::ProcessSP process_sp;
- if (crash_file)
- process_sp.reset(new ProcessElfCore (target, listener, *crash_file));
+ if (crash_file)
+ {
+ // Read enough data for a ELF32 header or ELF64 header
+ const size_t header_size = sizeof(llvm::ELF::Elf64_Ehdr);
+
+ lldb::DataBufferSP data_sp (crash_file->ReadFileContents(0, header_size));
+ if (data_sp && data_sp->GetByteSize() == header_size &&
+ elf::ELFHeader::MagicBytesMatch (data_sp->GetBytes()))
+ {
+ elf::ELFHeader elf_header;
+ DataExtractor data(data_sp, lldb::eByteOrderLittle, 4);
+ lldb::offset_t data_offset = 0;
+ if (elf_header.Parse(data, &data_offset))
+ {
+ if (elf_header.e_type == llvm::ELF::ET_CORE)
+ process_sp.reset(new ProcessElfCore (target, listener, *crash_file));
+ }
+ }
+ }
return process_sp;
}
@@ -66,7 +88,7 @@ ProcessElfCore::CanDebug(Target &target, bool plugin_specified_by_name)
if (!m_core_module_sp && m_core_file.Exists())
{
ModuleSpec core_module_spec(m_core_file, target.GetArchitecture());
- Error error (ModuleList::GetSharedModule (core_module_spec, m_core_module_sp,
+ Error error (ModuleList::GetSharedModule (core_module_spec, m_core_module_sp,
NULL, NULL, NULL));
if (m_core_module_sp)
{
@@ -87,6 +109,7 @@ ProcessElfCore::ProcessElfCore(Target& target, Listener &listener,
m_core_module_sp (),
m_core_file (core_file),
m_dyld_plugin_name (),
+ m_os(llvm::Triple::UnknownOS),
m_thread_data_valid(false),
m_thread_data(),
m_core_aranges ()
@@ -154,21 +177,21 @@ ProcessElfCore::DoLoadCore ()
Error error;
if (!m_core_module_sp)
{
- error.SetErrorString ("invalid core module");
+ error.SetErrorString ("invalid core module");
return error;
}
ObjectFileELF *core = (ObjectFileELF *)(m_core_module_sp->GetObjectFile());
if (core == NULL)
{
- error.SetErrorString ("invalid core object file");
+ error.SetErrorString ("invalid core object file");
return error;
}
const uint32_t num_segments = core->GetProgramHeaderCount();
if (num_segments == 0)
{
- error.SetErrorString ("core file has no sections");
+ error.SetErrorString ("core file has no sections");
return error;
}
@@ -209,7 +232,25 @@ ProcessElfCore::DoLoadCore ()
// it to match the core file which is always single arch.
ArchSpec arch (m_core_module_sp->GetArchitecture());
if (arch.IsValid())
- m_target.SetArchitecture(arch);
+ m_target.SetArchitecture(arch);
+
+ switch (m_os)
+ {
+ case llvm::Triple::FreeBSD:
+ {
+ static UnixSignalsSP s_freebsd_signals_sp(new FreeBSDSignals ());
+ SetUnixSignals(s_freebsd_signals_sp);
+ break;
+ }
+ case llvm::Triple::Linux:
+ {
+ static UnixSignalsSP s_linux_signals_sp(new process_linux::LinuxSignals ());
+ SetUnixSignals(s_linux_signals_sp);
+ break;
+ }
+ default:
+ break;
+ }
return error;
}
@@ -324,13 +365,17 @@ void
ProcessElfCore::Clear()
{
m_thread_list.Clear();
+ m_os = llvm::Triple::UnknownOS;
+
+ static UnixSignalsSP s_default_unix_signals_sp(new UnixSignals());
+ SetUnixSignals(s_default_unix_signals_sp);
}
void
ProcessElfCore::Initialize()
{
static bool g_initialized = false;
-
+
if (g_initialized == false)
{
g_initialized = true;
@@ -378,7 +423,7 @@ ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data,
arch.GetMachine() == llvm::Triple::x86_64);
int pr_version = data.GetU32(&offset);
- Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ Log *log (GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
if (log)
{
if (pr_version > 1)
@@ -395,7 +440,7 @@ ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data,
offset += 4; // pr_pid
if (lp64)
offset += 4;
-
+
size_t len = data.GetByteSize() - offset;
thread_data.gpregset = DataExtractor(data, offset, len);
}
@@ -421,7 +466,7 @@ ParseFreeBSDThrMisc(ThreadData &thread_data, DataExtractor &data)
/// a) Each thread context(2 or more NOTE entries) contained in its own segment (PT_NOTE)
/// b) All thread context is stored in a single segment(PT_NOTE).
/// This case is little tricker since while parsing we have to find where the
-/// new thread starts. The current implementation marks beginning of
+/// new thread starts. The current implementation marks beginning of
/// new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry.
/// For case (b) there may be either one NT_PRPSINFO per thread, or a single
/// one that applies to all threads (depending on the platform type).
@@ -468,6 +513,7 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *
DataExtractor note_data (segment_data, note_start, note_size);
if (note.n_name == "FreeBSD")
{
+ m_os = llvm::Triple::FreeBSD;
switch (note.n_type)
{
case NT_FREEBSD_PRSTATUS:
@@ -553,4 +599,3 @@ ProcessElfCore::GetAuxvData()
lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(start, len));
return buffer;
}
-
diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.h b/source/Plugins/Process/elf-core/ProcessElfCore.h
index 1c1ed98ce17a..2fc2e4ee7949 100644
--- a/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -37,45 +37,45 @@ public:
// Constructors and Destructors
//------------------------------------------------------------------
static lldb::ProcessSP
- CreateInstance (lldb_private::Target& target,
- lldb_private::Listener &listener,
+ CreateInstance (lldb_private::Target& target,
+ lldb_private::Listener &listener,
const lldb_private::FileSpec *crash_file_path);
-
+
static void
Initialize();
-
+
static void
Terminate();
-
+
static lldb_private::ConstString
GetPluginNameStatic();
-
+
static const char *
GetPluginDescriptionStatic();
-
+
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
- ProcessElfCore(lldb_private::Target& target,
+ ProcessElfCore(lldb_private::Target& target,
lldb_private::Listener &listener,
const lldb_private::FileSpec &core_file);
-
+
virtual
~ProcessElfCore();
-
+
//------------------------------------------------------------------
// Check if a given Process
//------------------------------------------------------------------
virtual bool
CanDebug (lldb_private::Target &target,
bool plugin_specified_by_name);
-
+
//------------------------------------------------------------------
// Creating a new process, or attaching to an existing one
//------------------------------------------------------------------
virtual lldb_private::Error
DoLoadCore ();
-
+
virtual lldb_private::DynamicLoader *
GetDynamicLoader ();
@@ -84,19 +84,19 @@ public:
//------------------------------------------------------------------
virtual lldb_private::ConstString
GetPluginName();
-
+
virtual uint32_t
GetPluginVersion();
-
+
//------------------------------------------------------------------
// Process Control
- //------------------------------------------------------------------
+ //------------------------------------------------------------------
virtual lldb_private::Error
DoDestroy ();
-
+
virtual void
RefreshStateAfterStop();
-
+
//------------------------------------------------------------------
// Process Queries
//------------------------------------------------------------------
@@ -108,10 +108,10 @@ public:
//------------------------------------------------------------------
virtual size_t
ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
-
+
virtual size_t
DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
-
+
virtual lldb::addr_t
GetImageInfoAddress ();
@@ -120,16 +120,16 @@ public:
// Returns AUXV structure found in the core file
const lldb::DataBufferSP
- GetAuxvData();
+ GetAuxvData() override;
protected:
void
Clear ( );
-
+
virtual bool
- UpdateThreadList (lldb_private::ThreadList &old_thread_list,
+ UpdateThreadList (lldb_private::ThreadList &old_thread_list,
lldb_private::ThreadList &new_thread_list);
-
+
private:
//------------------------------------------------------------------
// For ProcessElfCore only
@@ -142,6 +142,8 @@ private:
std::string m_dyld_plugin_name;
DISALLOW_COPY_AND_ASSIGN (ProcessElfCore);
+ llvm::Triple::OSType m_os;
+
// True if m_thread_contexts contains valid entries
bool m_thread_data_valid;
diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp
index b95a51130ca7..fbf397b933cc 100644
--- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp
+++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp
@@ -21,13 +21,9 @@ RegisterContextCorePOSIX_mips64::RegisterContextCorePOSIX_mips64(Thread &thread,
const DataExtractor &fpregset)
: RegisterContextPOSIX_mips64(thread, 0, register_info)
{
- size_t i;
- lldb::offset_t offset = 0;
-
- for (i = 0; i < k_num_gpr_registers_mips64; i++)
- {
- m_reg[i] = gpregset.GetU64(&offset);
- }
+ m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize()));
+ m_gpr.SetData(m_gpr_buffer);
+ m_gpr.SetByteOrder(gpregset.GetByteOrder());
}
RegisterContextCorePOSIX_mips64::~RegisterContextCorePOSIX_mips64()
@@ -63,10 +59,14 @@ RegisterContextCorePOSIX_mips64::WriteFPR()
bool
RegisterContextCorePOSIX_mips64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
{
- int reg_num = reg_info->byte_offset / 8;
- assert(reg_num < k_num_gpr_registers_mips64);
- value = m_reg[reg_num];
- return true;
+ lldb::offset_t offset = reg_info->byte_offset;
+ uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
+ if (offset == reg_info->byte_offset + reg_info->byte_size)
+ {
+ value = v;
+ return true;
+ }
+ return false;
}
bool
diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h
index 92e486bf2235..ca29d4f0febd 100644
--- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h
+++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h
@@ -10,14 +10,15 @@
#ifndef liblldb_RegisterContextCorePOSIX_mips64_H_
#define liblldb_RegisterContextCorePOSIX_mips64_H_
-#include "Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
class RegisterContextCorePOSIX_mips64 :
public RegisterContextPOSIX_mips64
{
public:
RegisterContextCorePOSIX_mips64 (lldb_private::Thread &thread,
- RegisterInfoInterface *register_info,
+ lldb_private::RegisterInfoInterface *register_info,
const lldb_private::DataExtractor &gpregset,
const lldb_private::DataExtractor &fpregset);
@@ -52,7 +53,8 @@ protected:
WriteFPR();
private:
- uint64_t m_reg[40];
+ lldb::DataBufferSP m_gpr_buffer;
+ lldb_private::DataExtractor m_gpr;
};
#endif // #ifndef liblldb_RegisterContextCorePOSIX_mips64_H_
diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h
index d4ea14fab7b1..ac0f49c3db52 100644
--- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h
+++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h
@@ -10,14 +10,14 @@
#ifndef liblldb_RegisterContextCorePOSIX_x86_64_H_
#define liblldb_RegisterContextCorePOSIX_x86_64_H_
-#include "Plugins/Process/POSIX/RegisterContextPOSIX_x86.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h"
class RegisterContextCorePOSIX_x86_64 :
public RegisterContextPOSIX_x86
{
public:
RegisterContextCorePOSIX_x86_64 (lldb_private::Thread &thread,
- RegisterInfoInterface *register_info,
+ lldb_private::RegisterInfoInterface *register_info,
const lldb_private::DataExtractor &gpregset,
const lldb_private::DataExtractor &fpregset);
diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/source/Plugins/Process/elf-core/ThreadElfCore.cpp
index cadcf53ca543..d9f6cc04a343 100644
--- a/source/Plugins/Process/elf-core/ThreadElfCore.cpp
+++ b/source/Plugins/Process/elf-core/ThreadElfCore.cpp
@@ -8,11 +8,11 @@
//===----------------------------------------------------------------------===//
#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Unwind.h"
-#include "ProcessPOSIXLog.h"
#include "ThreadElfCore.h"
#include "ProcessElfCore.h"
@@ -74,7 +74,7 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)
{
RegisterContextSP reg_ctx_sp;
uint32_t concrete_frame_idx = 0;
- Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ Log *log (GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
if (frame)
concrete_frame_idx = frame->GetConcreteFrameIndex ();
@@ -108,7 +108,7 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)
}
break;
}
-
+
case llvm::Triple::Linux:
{
switch (arch.GetMachine())
diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.h b/source/Plugins/Process/elf-core/ThreadElfCore.h
index 2661edfa50cd..f1f00cf019b3 100644
--- a/source/Plugins/Process/elf-core/ThreadElfCore.h
+++ b/source/Plugins/Process/elf-core/ThreadElfCore.h
@@ -40,7 +40,7 @@ struct ELFLinuxPrStatus
int32_t si_errno;
int16_t pr_cursig;
-
+
uint64_t pr_sigpend;
uint64_t pr_sighold;
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index 72600d835934..1f4dd93976ec 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -22,14 +22,21 @@
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/Socket.h"
#include "lldb/Host/TimeValue.h"
#include "lldb/Target/Process.h"
// Project includes
#include "ProcessGDBRemoteLog.h"
-#define DEBUGSERVER_BASENAME "debugserver"
+#if defined(__APPLE__)
+# define DEBUGSERVER_BASENAME "debugserver"
+#else
+# define DEBUGSERVER_BASENAME "lldb-gdbserver"
+#endif
using namespace lldb;
using namespace lldb_private;
@@ -321,6 +328,7 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac
switch (status)
{
case eConnectionStatusTimedOut:
+ case eConnectionStatusInterrupted:
timed_out = true;
break;
case eConnectionStatusSuccess:
@@ -457,7 +465,8 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
assert (content_length <= m_bytes.size());
assert (total_length <= m_bytes.size());
assert (content_length <= total_length);
-
+ const size_t content_end = content_start + content_length;
+
bool success = true;
std::string &packet_str = packet.GetStringRef();
@@ -471,7 +480,45 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
if (!m_history.DidDumpToLog ())
m_history.Dump (log);
- log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str());
+ bool binary = false;
+ // Only detect binary for packets that start with a '$' and have a '#CC' checksum
+ if (m_bytes[0] == '$' && total_length > 4)
+ {
+ for (size_t i=0; !binary && i<total_length; ++i)
+ {
+ if (isprint(m_bytes[i]) == 0)
+ binary = true;
+ }
+ }
+ if (binary)
+ {
+ StreamString strm;
+ // Packet header...
+ strm.Printf("<%4" PRIu64 "> read packet: %c", (uint64_t)total_length, m_bytes[0]);
+ for (size_t i=content_start; i<content_end; ++i)
+ {
+ // Remove binary escaped bytes when displaying the packet...
+ const char ch = m_bytes[i];
+ if (ch == 0x7d)
+ {
+ // 0x7d is the escape character. The next character is to
+ // be XOR'd with 0x20.
+ const char escapee = m_bytes[++i] ^ 0x20;
+ strm.Printf("%2.2x", escapee);
+ }
+ else
+ {
+ strm.Printf("%2.2x", (uint8_t)ch);
+ }
+ }
+ // Packet footer...
+ strm.Printf("%c%c%c", m_bytes[total_length-3], m_bytes[total_length-2], m_bytes[total_length-1]);
+ log->PutCString(strm.GetString().c_str());
+ }
+ else
+ {
+ log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str());
+ }
}
m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length);
@@ -482,7 +529,7 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
// run-length encoding in the process.
// Reserve enough byte for the most common case (no RLE used)
packet_str.reserve(m_bytes.length());
- for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_start + content_length; ++c)
+ for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_end; ++c)
{
if (*c == '*')
{
@@ -610,6 +657,10 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
lldb_private::ProcessLaunchInfo &launch_info,
uint16_t &out_port)
{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s(hostname=%s, in_port=%" PRIu16 ", out_port=%" PRIu16, __FUNCTION__, hostname ? hostname : "<empty>", in_port, out_port);
+
out_port = in_port;
Error error;
// If we locate debugserver, keep that located version around
@@ -622,24 +673,34 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
// to the debugserver to use and use it if we do.
const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH");
if (env_debugserver_path)
+ {
debugserver_file_spec.SetFile (env_debugserver_path, false);
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s() gdb-remote stub exe path set from environment variable: %s", __FUNCTION__, env_debugserver_path);
+ }
else
debugserver_file_spec = g_debugserver_file_spec;
bool debugserver_exists = debugserver_file_spec.Exists();
if (!debugserver_exists)
{
// The debugserver binary is in the LLDB.framework/Resources
- // directory.
- if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec))
+ // directory.
+ if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, debugserver_file_spec))
{
- debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME);
+ debugserver_file_spec.AppendPathComponent (DEBUGSERVER_BASENAME);
debugserver_exists = debugserver_file_spec.Exists();
if (debugserver_exists)
{
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ());
+
g_debugserver_file_spec = debugserver_file_spec;
}
else
{
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ());
+
g_debugserver_file_spec.Clear();
debugserver_file_spec.Clear();
}
@@ -690,9 +751,9 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
// Binding to port zero, we need to figure out what port it ends up
// using using a named pipe...
FileSpec tmpdir_file_spec;
- if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
{
- tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX");
+ tmpdir_file_spec.AppendPathComponent("debugserver-named-pipe.XXXXXX");
strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path));
}
else
@@ -702,7 +763,7 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
if (::mktemp (named_pipe_path))
{
-#if defined(_MSC_VER)
+#if defined(_WIN32)
if ( false )
#else
if (::mkfifo(named_pipe_path, 0600) == 0)
@@ -722,21 +783,28 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
{
// No host and port given, so lets listen on our end and make the debugserver
// connect to us..
- error = StartListenThread ("localhost", 0);
+ error = StartListenThread ("127.0.0.1", 0);
if (error.Fail())
return error;
ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection ();
- out_port = connection->GetBoundPort(3);
- assert (out_port != 0);
- char port_cstr[32];
- snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", out_port);
- // Send the host and port down that debugserver and specify an option
- // so that it connects back to the port we are listening to in this process
- debugserver_args.AppendArgument("--reverse-connect");
- debugserver_args.AppendArgument(port_cstr);
+ // Wait for 10 seconds to resolve the bound port
+ out_port = connection->GetListeningPort(10);
+ if (out_port > 0)
+ {
+ char port_cstr[32];
+ snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", out_port);
+ // Send the host and port down that debugserver and specify an option
+ // so that it connects back to the port we are listening to in this process
+ debugserver_args.AppendArgument("--reverse-connect");
+ debugserver_args.AppendArgument(port_cstr);
+ }
+ else
+ {
+ error.SetErrorString ("failed to bind to port 0 on 127.0.0.1");
+ return error;
+ }
}
-
const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
if (env_debugserver_log_file)
@@ -751,7 +819,25 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);
debugserver_args.AppendArgument(arg_cstr);
}
-
+
+ // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an env var doesn't come back.
+ uint32_t env_var_index = 1;
+ bool has_env_var;
+ do
+ {
+ char env_var_name[64];
+ snprintf (env_var_name, sizeof (env_var_name), "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++);
+ const char *extra_arg = getenv(env_var_name);
+ has_env_var = extra_arg != nullptr;
+
+ if (has_env_var)
+ {
+ debugserver_args.AppendArgument (extra_arg);
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s adding env var %s contents to stub command line (%s)", __FUNCTION__, env_var_name, extra_arg);
+ }
+ } while (has_env_var);
+
// Close STDIN, STDOUT and STDERR. We might need to redirect them
// to "/dev/null" if we run into any problems.
launch_info.AppendCloseFileAction (STDIN_FILENO);
@@ -760,31 +846,34 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
error = Host::LaunchProcess(launch_info);
- if (named_pipe_path[0])
+ if (error.Success() && launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
{
- File name_pipe_file;
- error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead);
- if (error.Success())
+ if (named_pipe_path[0])
{
- char port_cstr[256];
- port_cstr[0] = '\0';
- size_t num_bytes = sizeof(port_cstr);
- error = name_pipe_file.Read(port_cstr, num_bytes);
- assert (error.Success());
- assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0');
- out_port = Args::StringToUInt32(port_cstr, 0);
- name_pipe_file.Close();
+ File name_pipe_file;
+ error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead);
+ if (error.Success())
+ {
+ char port_cstr[256];
+ port_cstr[0] = '\0';
+ size_t num_bytes = sizeof(port_cstr);
+ error = name_pipe_file.Read(port_cstr, num_bytes);
+ assert (error.Success());
+ assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0');
+ out_port = Args::StringToUInt32(port_cstr, 0);
+ name_pipe_file.Close();
+ }
+ FileSystem::Unlink(named_pipe_path);
+ }
+ else if (listen)
+ {
+
+ }
+ else
+ {
+ // Make sure we actually connect with the debugserver...
+ JoinListenThread();
}
- Host::Unlink(named_pipe_path);
- }
- else if (listen)
- {
-
- }
- else
- {
- // Make sure we actually connect with the debugserver...
- JoinListenThread();
}
}
else
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
index d8361113ddc8..b11d38563207 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -271,7 +271,7 @@ protected:
lldb_private::Error
- StartListenThread (const char *hostname = "localhost",
+ StartListenThread (const char *hostname = "127.0.0.1",
uint16_t port = 0);
bool
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index ab3bf7f5aa2a..5e4ed7648f95 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -17,6 +17,7 @@
#include <sstream>
// Other libraries and framework includes
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Core/ConnectionFileDescriptor.h"
@@ -26,7 +27,9 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Host/TimeValue.h"
+#include "lldb/Target/Target.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
@@ -37,7 +40,7 @@
using namespace lldb;
using namespace lldb_private;
-#ifdef LLDB_DISABLE_POSIX
+#if defined(LLDB_DISABLE_POSIX) && !defined(SIGSTOP)
#define SIGSTOP 17
#endif
@@ -56,7 +59,9 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_supports_vCont_s (eLazyBoolCalculate),
m_supports_vCont_S (eLazyBoolCalculate),
m_qHostInfo_is_valid (eLazyBoolCalculate),
+ m_curr_pid_is_valid (eLazyBoolCalculate),
m_qProcessInfo_is_valid (eLazyBoolCalculate),
+ m_qGDBServerVersion_is_valid (eLazyBoolCalculate),
m_supports_alloc_dealloc_memory (eLazyBoolCalculate),
m_supports_memory_region_info (eLazyBoolCalculate),
m_supports_watchpoint_support_info (eLazyBoolCalculate),
@@ -65,10 +70,14 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_attach_or_wait_reply(eLazyBoolCalculate),
m_prepare_for_reg_writing_reply (eLazyBoolCalculate),
m_supports_p (eLazyBoolCalculate),
+ m_supports_x (eLazyBoolCalculate),
+ m_avoid_g_packets (eLazyBoolCalculate),
m_supports_QSaveRegisterState (eLazyBoolCalculate),
+ m_supports_qXfer_auxv_read (eLazyBoolCalculate),
m_supports_qXfer_libraries_read (eLazyBoolCalculate),
m_supports_qXfer_libraries_svr4_read (eLazyBoolCalculate),
m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate),
+ m_supports_jThreadExtendedInfo (eLazyBoolCalculate),
m_supports_qProcessInfoPID (true),
m_supports_qfProcessInfo (true),
m_supports_qUserName (true),
@@ -81,6 +90,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_supports_z4 (true),
m_supports_QEnvironment (true),
m_supports_QEnvironmentHexEncoded (true),
+ m_curr_pid (LLDB_INVALID_PROCESS_ID),
m_curr_tid (LLDB_INVALID_THREAD_ID),
m_curr_tid_run (LLDB_INVALID_THREAD_ID),
m_num_supported_hardware_watchpoints (0),
@@ -90,6 +100,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_async_result (PacketResult::Success),
m_async_response (),
m_async_signal (-1),
+ m_interrupt_sent (false),
m_thread_id_to_used_usec_map (),
m_host_arch(),
m_process_arch(),
@@ -99,6 +110,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_os_build (),
m_os_kernel (),
m_hostname (),
+ m_gdb_server_name(),
+ m_gdb_server_version(UINT32_MAX),
m_default_packet_timeout (0),
m_max_packet_size (0)
{
@@ -187,6 +200,16 @@ GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported ()
return (m_supports_qXfer_libraries_read == eLazyBoolYes);
}
+bool
+GDBRemoteCommunicationClient::GetQXferAuxvReadSupported ()
+{
+ if (m_supports_qXfer_auxv_read == eLazyBoolCalculate)
+ {
+ GetRemoteQSupported();
+ }
+ return (m_supports_qXfer_auxv_read == eLazyBoolYes);
+}
+
uint64_t
GDBRemoteCommunicationClient::GetRemoteMaxPacketSize()
{
@@ -205,8 +228,18 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported ()
m_send_acks = true;
m_supports_not_sending_acks = eLazyBoolNo;
+ // This is the first real packet that we'll send in a debug session and it may take a little
+ // longer than normal to receive a reply. Wait at least 6 seconds for a reply to this packet.
+
+ const uint32_t minimum_timeout = 6;
+ uint32_t old_timeout = GetPacketTimeoutInMicroSeconds() / lldb_private::TimeValue::MicroSecPerSec;
+ SetPacketTimeout (std::max (old_timeout, minimum_timeout));
+
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success)
+ PacketResult packet_send_result = SendPacketAndWaitForResponse("QStartNoAckMode", response, false);
+ SetPacketTimeout (old_timeout);
+
+ if (packet_send_result == PacketResult::Success)
{
if (response.IsOKResponse())
{
@@ -287,13 +320,18 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings()
m_supports_vCont_s = eLazyBoolCalculate;
m_supports_vCont_S = eLazyBoolCalculate;
m_supports_p = eLazyBoolCalculate;
+ m_supports_x = eLazyBoolCalculate;
m_supports_QSaveRegisterState = eLazyBoolCalculate;
m_qHostInfo_is_valid = eLazyBoolCalculate;
+ m_curr_pid_is_valid = eLazyBoolCalculate;
m_qProcessInfo_is_valid = eLazyBoolCalculate;
+ m_qGDBServerVersion_is_valid = eLazyBoolCalculate;
m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
m_supports_memory_region_info = eLazyBoolCalculate;
m_prepare_for_reg_writing_reply = eLazyBoolCalculate;
m_attach_or_wait_reply = eLazyBoolCalculate;
+ m_avoid_g_packets = eLazyBoolCalculate;
+ m_supports_qXfer_auxv_read = eLazyBoolCalculate;
m_supports_qXfer_libraries_read = eLazyBoolCalculate;
m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate;
m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate;
@@ -310,8 +348,18 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings()
m_supports_z4 = true;
m_supports_QEnvironment = true;
m_supports_QEnvironmentHexEncoded = true;
+
m_host_arch.Clear();
m_process_arch.Clear();
+ m_os_version_major = UINT32_MAX;
+ m_os_version_minor = UINT32_MAX;
+ m_os_version_update = UINT32_MAX;
+ m_os_build.clear();
+ m_os_kernel.clear();
+ m_hostname.clear();
+ m_gdb_server_name.clear();
+ m_gdb_server_version = UINT32_MAX;
+ m_default_packet_timeout = 0;
m_max_packet_size = 0;
}
@@ -320,8 +368,9 @@ void
GDBRemoteCommunicationClient::GetRemoteQSupported ()
{
// Clear out any capabilities we expect to see in the qSupported response
- m_supports_qXfer_libraries_svr4_read = eLazyBoolNo;
+ m_supports_qXfer_auxv_read = eLazyBoolNo;
m_supports_qXfer_libraries_read = eLazyBoolNo;
+ m_supports_qXfer_libraries_svr4_read = eLazyBoolNo;
m_supports_augmented_libraries_svr4_read = eLazyBoolNo;
m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if not, we assume no limit
@@ -331,6 +380,8 @@ GDBRemoteCommunicationClient::GetRemoteQSupported ()
/*send_async=*/false) == PacketResult::Success)
{
const char *response_cstr = response.GetStringRef().c_str();
+ if (::strstr (response_cstr, "qXfer:auxv:read+"))
+ m_supports_qXfer_auxv_read = eLazyBoolYes;
if (::strstr (response_cstr, "qXfer:libraries-svr4:read+"))
m_supports_qXfer_libraries_svr4_read = eLazyBoolYes;
if (::strstr (response_cstr, "augmented-libraries-svr4-read"))
@@ -457,6 +508,42 @@ GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid)
return m_supports_p;
}
+bool
+GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported ()
+{
+ if (m_supports_jThreadExtendedInfo == eLazyBoolCalculate)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_jThreadExtendedInfo = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ m_supports_jThreadExtendedInfo = eLazyBoolYes;
+ }
+ }
+ }
+ return m_supports_jThreadExtendedInfo;
+}
+
+bool
+GDBRemoteCommunicationClient::GetxPacketSupported ()
+{
+ if (m_supports_x == eLazyBoolCalculate)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_x = eLazyBoolNo;
+ char packet[256];
+ snprintf (packet, sizeof (packet), "x0,0");
+ if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ m_supports_x = eLazyBoolYes;
+ }
+ }
+ return m_supports_x;
+}
+
GDBRemoteCommunicationClient::PacketResult
GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses
(
@@ -502,11 +589,8 @@ GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses
{
return PacketResult::ErrorReplyInvalid;
}
- // Skip past m or l
- const char *s = this_string.c_str() + 1;
-
- // Concatenate the result so far
- response_string += s;
+ // Concatenate the result so far (skipping 'm' or 'l')
+ response_string.append(this_string, 1, std::string::npos);
if (first_char == 'l')
// We're done
return PacketResult::Success;
@@ -550,7 +634,6 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse
PacketResult packet_result = PacketResult::ErrorSendFailed;
Mutex::Locker locker;
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
- size_t response_len = 0;
if (GetSequenceMutex (locker))
{
packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response);
@@ -588,7 +671,6 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse
// Swap the response buffer to avoid malloc and string copy
response.GetStringRef().swap (m_async_response.GetStringRef());
- response_len = response.GetStringRef().size();
packet_result = m_async_result;
}
else
@@ -772,6 +854,8 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse
log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str());
if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success)
state = eStateInvalid;
+ else
+ m_interrupt_sent = false;
m_private_is_running.SetValue (true, eBroadcastAlways);
}
@@ -1047,7 +1131,7 @@ GDBRemoteCommunicationClient::SendAsyncSignal (int signo)
// then the caller that requested the interrupt will want to keep the sequence
// locked down so that no one else can send packets while the caller has control.
// This function usually gets called when we are running and need to stop the
-// target. It can also be used when we are running and and we need to do something
+// target. It can also be used when we are running and we need to do something
// else (like read/write memory), so we need to interrupt the running process
// (gdb remote protocol requires this), and do what we need to do, then resume.
@@ -1128,13 +1212,40 @@ GDBRemoteCommunicationClient::SendInterrupt
lldb::pid_t
GDBRemoteCommunicationClient::GetCurrentProcessID ()
{
- StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success)
+ if (m_curr_pid_is_valid == eLazyBoolYes)
+ return m_curr_pid;
+
+ // First try to retrieve the pid via the qProcessInfo request.
+ GetCurrentProcessInfo ();
+ if (m_curr_pid_is_valid == eLazyBoolYes)
+ {
+ // We really got it.
+ return m_curr_pid;
+ }
+ else
{
- if (response.GetChar() == 'Q')
- if (response.GetChar() == 'C')
- return response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID);
+ // If we don't get a response for qProcessInfo, check if $qC gives us a result.
+ // $qC only returns a real process id on older debugserver and lldb-platform stubs.
+ // The gdb remote protocol documents $qC as returning the thread id, which newer
+ // debugserver and lldb-gdbserver stubs return correctly.
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success)
+ {
+ if (response.GetChar() == 'Q')
+ {
+ if (response.GetChar() == 'C')
+ {
+ m_curr_pid = response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID);
+ if (m_curr_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ m_curr_pid_is_valid = eLazyBoolYes;
+ return m_curr_pid;
+ }
+ }
+ }
+ }
}
+
return LLDB_INVALID_PROCESS_ID;
}
@@ -1168,7 +1279,7 @@ int
GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &launch_info)
{
// Since we don't get the send argv0 separate from the executable path, we need to
- // make sure to use the actual exectuable path found in the launch_info...
+ // make sure to use the actual executable path found in the launch_info...
std::vector<const char *> argv;
FileSpec exe_file = launch_info.GetExecutableFile();
std::string exe_path;
@@ -1304,6 +1415,41 @@ GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch)
return -1;
}
+int
+GDBRemoteCommunicationClient::SendLaunchEventDataPacket (char const *data, bool *was_supported)
+{
+ if (data && *data != '\0')
+ {
+ StreamString packet;
+ packet.Printf("QSetProcessEvent:%s", data);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ if (was_supported)
+ *was_supported = true;
+ return 0;
+ }
+ else if (response.IsUnsupportedResponse())
+ {
+ if (was_supported)
+ *was_supported = false;
+ return -1;
+ }
+ else
+ {
+ uint8_t error = response.GetError();
+ if (was_supported)
+ *was_supported = true;
+ if (error)
+ return error;
+ }
+ }
+ }
+ return -1;
+}
+
bool
GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major,
uint32_t &minor,
@@ -1384,10 +1530,75 @@ GDBRemoteCommunicationClient::GetProcessArchitecture ()
return m_process_arch;
}
+bool
+GDBRemoteCommunicationClient::GetGDBServerVersion()
+{
+ if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate)
+ {
+ m_gdb_server_name.clear();
+ m_gdb_server_version = 0;
+ m_qGDBServerVersion_is_valid = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qGDBServerVersion", response, false) == PacketResult::Success)
+ {
+ if (response.IsNormalResponse())
+ {
+ std::string name;
+ std::string value;
+ bool success = false;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("name") == 0)
+ {
+ success = true;
+ m_gdb_server_name.swap(value);
+ }
+ else if (name.compare("version") == 0)
+ {
+ size_t dot_pos = value.find('.');
+ if (dot_pos != std::string::npos)
+ value[dot_pos] = '\0';
+ const uint32_t version = Args::StringToUInt32(value.c_str(), UINT32_MAX, 0);
+ if (version != UINT32_MAX)
+ {
+ success = true;
+ m_gdb_server_version = version;
+ }
+ }
+ }
+ if (success)
+ m_qGDBServerVersion_is_valid = eLazyBoolYes;
+ }
+ }
+ }
+ return m_qGDBServerVersion_is_valid == eLazyBoolYes;
+}
+
+const char *
+GDBRemoteCommunicationClient::GetGDBServerProgramName()
+{
+ if (GetGDBServerVersion())
+ {
+ if (!m_gdb_server_name.empty())
+ return m_gdb_server_name.c_str();
+ }
+ return NULL;
+}
+
+uint32_t
+GDBRemoteCommunicationClient::GetGDBServerProgramVersion()
+{
+ if (GetGDBServerVersion())
+ return m_gdb_server_version;
+ return 0;
+}
bool
GDBRemoteCommunicationClient::GetHostInfo (bool force)
{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS));
+
if (force || m_qHostInfo_is_valid == eLazyBoolCalculate)
{
m_qHostInfo_is_valid = eLazyBoolNo;
@@ -1432,10 +1643,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force)
}
else if (name.compare("triple") == 0)
{
- // The triple comes as ASCII hex bytes since it contains '-' chars
- extractor.GetStringRef().swap(value);
- extractor.SetFilePos(0);
- extractor.GetHexByteString (triple);
+ triple.swap(value);
++num_keys_decoded;
}
else if (name.compare ("distribution_id") == 0)
@@ -1548,6 +1756,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force)
{
switch (m_host_arch.GetMachine())
{
+ case llvm::Triple::aarch64:
case llvm::Triple::arm:
case llvm::Triple::thumb:
os_name = "ios";
@@ -1588,6 +1797,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force)
{
switch (m_host_arch.GetMachine())
{
+ case llvm::Triple::aarch64:
case llvm::Triple::arm:
case llvm::Triple::thumb:
host_triple.setOS(llvm::Triple::IOS);
@@ -1619,6 +1829,9 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force)
{
assert (byte_order == m_host_arch.GetByteOrder());
}
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s parsed host architecture as %s, triple as %s from triple text %s", __FUNCTION__, m_host_arch.GetArchitectureName () ? m_host_arch.GetArchitectureName () : "<null-arch-name>", m_host_arch.GetTriple ().getTriple ().c_str(), triple.c_str ());
}
if (!distribution_id.empty ())
m_host_arch.SetDistributionId (distribution_id.c_str ());
@@ -1682,7 +1895,9 @@ GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions)
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
{
- if (!response.IsErrorResponse())
+ if (response.IsUnsupportedResponse())
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ else if (!response.IsErrorResponse())
return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
}
else
@@ -1705,7 +1920,9 @@ GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr)
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
{
- if (response.IsOKResponse())
+ if (response.IsUnsupportedResponse())
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ else if (response.IsOKResponse())
return true;
}
else
@@ -1746,14 +1963,16 @@ GDBRemoteCommunicationClient::Detach (bool keep_stopped)
}
else
{
- PacketResult packet_result = SendPacket ("D1", 2);
+ StringExtractorGDBRemote response;
+ PacketResult packet_result = SendPacketAndWaitForResponse ("D1", 1, response, false);
if (packet_result != PacketResult::Success)
error.SetErrorString ("Sending extended disconnect packet failed.");
}
}
else
{
- PacketResult packet_result = SendPacket ("D", 1);
+ StringExtractorGDBRemote response;
+ PacketResult packet_result = SendPacketAndWaitForResponse ("D", 1, response, false);
if (packet_result != PacketResult::Success)
error.SetErrorString ("Sending disconnect packet failed.");
}
@@ -2051,6 +2270,25 @@ GDBRemoteCommunicationClient::SetDisableASLR (bool enable)
return -1;
}
+int
+GDBRemoteCommunicationClient::SetDetachOnError (bool enable)
+{
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDetachOnError:%i", enable ? 1 : 0);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ return -1;
+}
+
+
bool
GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info)
{
@@ -2093,10 +2331,6 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot
}
else if (name.compare("triple") == 0)
{
- // The triple comes as ASCII hex bytes since it contains '-' chars
- extractor.GetStringRef().swap(value);
- extractor.SetFilePos(0);
- extractor.GetHexByteString (value);
process_info.GetArchitecture ().SetTriple (value.c_str());
}
else if (name.compare("name") == 0)
@@ -2192,8 +2426,8 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo ()
std::string triple;
uint32_t pointer_byte_size = 0;
StringExtractor extractor;
- ByteOrder byte_order = eByteOrderInvalid;
uint32_t num_keys_decoded = 0;
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
while (response.GetNameColonValue(name, value))
{
if (name.compare("cputype") == 0)
@@ -2208,6 +2442,11 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo ()
if (sub != 0)
++num_keys_decoded;
}
+ else if (name.compare("triple") == 0)
+ {
+ triple = value;
+ ++num_keys_decoded;
+ }
else if (name.compare("ostype") == 0)
{
os_name.swap (value);
@@ -2220,15 +2459,10 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo ()
}
else if (name.compare("endian") == 0)
{
- ++num_keys_decoded;
- if (value.compare("little") == 0)
- byte_order = eByteOrderLittle;
- else if (value.compare("big") == 0)
- byte_order = eByteOrderBig;
- else if (value.compare("pdp") == 0)
- byte_order = eByteOrderPDP;
- else
- --num_keys_decoded;
+ if (value.compare("little") == 0 ||
+ value.compare("big") == 0 ||
+ value.compare("pdp") == 0)
+ ++num_keys_decoded;
}
else if (name.compare("ptrsize") == 0)
{
@@ -2236,20 +2470,42 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo ()
if (pointer_byte_size != 0)
++num_keys_decoded;
}
+ else if (name.compare("pid") == 0)
+ {
+ pid = Args::StringToUInt64(value.c_str(), 0, 16);
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ ++num_keys_decoded;
+ }
}
if (num_keys_decoded > 0)
m_qProcessInfo_is_valid = eLazyBoolYes;
- if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty())
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ m_curr_pid_is_valid = eLazyBoolYes;
+ m_curr_pid = pid;
+ }
+
+ // Set the ArchSpec from the triple if we have it.
+ if (!triple.empty ())
+ {
+ m_process_arch.SetTriple (triple.c_str ());
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_process_arch.GetAddressByteSize());
+ }
+ }
+ else if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty())
{
m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub);
if (pointer_byte_size)
{
assert (pointer_byte_size == m_process_arch.GetAddressByteSize());
}
+ m_process_arch.GetTriple().setOSName(llvm::StringRef (os_name));
m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name));
m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name));
- return true;
}
+ return true;
}
}
else
@@ -2333,7 +2589,7 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &mat
const ArchSpec &match_arch = match_info.GetProcessInfo().GetArchitecture();
const llvm::Triple &triple = match_arch.GetTriple();
packet.PutCString("triple:");
- packet.PutCStringAsRawHex8(triple.getTriple().c_str());
+ packet.PutCString(triple.getTriple().c_str());
packet.PutChar (';');
}
}
@@ -2429,8 +2685,8 @@ GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets)
{
static uint32_t g_send_sizes[] = { 0, 64, 128, 512, 1024 };
static uint32_t g_recv_sizes[] = { 0, 64, 128, 512, 1024 }; //, 4*1024, 8*1024, 16*1024, 32*1024, 48*1024, 64*1024, 96*1024, 128*1024 };
- const size_t k_num_send_sizes = sizeof(g_send_sizes)/sizeof(uint32_t);
- const size_t k_num_recv_sizes = sizeof(g_recv_sizes)/sizeof(uint32_t);
+ const size_t k_num_send_sizes = llvm::array_lengthof(g_send_sizes);
+ const size_t k_num_recv_sizes = llvm::array_lengthof(g_recv_sizes);
const uint64_t k_recv_amount = 4*1024*1024; // Receive 4MB
for (uint32_t send_idx = 0; send_idx < k_num_send_sizes; ++send_idx)
{
@@ -2539,7 +2795,7 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid, const
hostname = remote_accept_hostname;
else
{
- if (Host::GetHostname (hostname))
+ if (HostInfo::GetHostname(hostname))
{
// Make the GDB server we launch only accept connections from this host
stream.Printf("host:%s;", hostname.c_str());
@@ -2687,7 +2943,7 @@ GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type,
type,
addr,
length);
- // Check we havent overwritten the end of the packet buffer
+ // Check we haven't overwritten the end of the packet buffer
assert (packet_len + 1 < (int)sizeof(packet));
StringExtractorGDBRemote response;
// Try to send the breakpoint packet, and check that it was correctly sent
@@ -2715,7 +2971,7 @@ GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type,
}
}
}
- // Signal generic faliure
+ // Signal generic failure
return UINT8_MAX;
}
@@ -2977,7 +3233,7 @@ GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &fil
else
{
const uint32_t mode = response.GetS32(-1);
- if (mode == -1)
+ if (static_cast<int32_t>(mode) == -1)
{
if (response.GetChar() == ',')
{
@@ -3217,6 +3473,38 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s
}
bool
+GDBRemoteCommunicationClient::AvoidGPackets (ProcessGDBRemote *process)
+{
+ // Some targets have issues with g/G packets and we need to avoid using them
+ if (m_avoid_g_packets == eLazyBoolCalculate)
+ {
+ if (process)
+ {
+ m_avoid_g_packets = eLazyBoolNo;
+ const ArchSpec &arch = process->GetTarget().GetArchitecture();
+ if (arch.IsValid()
+ && arch.GetTriple().getVendor() == llvm::Triple::Apple
+ && arch.GetTriple().getOS() == llvm::Triple::IOS
+ && arch.GetTriple().getArch() == llvm::Triple::aarch64)
+ {
+ m_avoid_g_packets = eLazyBoolYes;
+ uint32_t gdb_server_version = GetGDBServerProgramVersion();
+ if (gdb_server_version != 0)
+ {
+ const char *gdb_server_name = GetGDBServerProgramName();
+ if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0)
+ {
+ if (gdb_server_version >= 310)
+ m_avoid_g_packets = eLazyBoolNo;
+ }
+ }
+ }
+ }
+ }
+ return m_avoid_g_packets == eLazyBoolYes;
+}
+
+bool
GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response)
{
Mutex::Locker locker;
@@ -3309,7 +3597,7 @@ GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save
bool
GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t save_id)
{
- // We use the "m_supports_QSaveRegisterState" variable here becuase the
+ // We use the "m_supports_QSaveRegisterState" variable here because the
// QSaveRegisterState and QRestoreRegisterState packets must both be supported in
// order to be useful
if (m_supports_QSaveRegisterState == eLazyBoolNo)
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index a1e982b3ec4e..fddcd6cd1426 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -92,7 +92,7 @@ public:
// indicates if the packet was send and any response was received
// even in the response is UNIMPLEMENTED. If the packet failed to
// get a response, then false is returned. This quickly tells us
- // if we were able to connect and communicte with the remote GDB
+ // if we were able to connect and communicate with the remote GDB
// server
bool
QueryNoAckModeSupported ();
@@ -159,6 +159,10 @@ public:
int
SendLaunchArchPacket (const char *arch);
+
+ int
+ SendLaunchEventDataPacket (const char *data, bool *was_supported = NULL);
+
//------------------------------------------------------------------
/// Sends a "vAttach:PID" where PID is in hex.
///
@@ -201,13 +205,25 @@ public:
/// be launched with the 'A' packet.
///
/// @param[in] enable
- /// A boolean value indicating wether to disable ASLR or not.
+ /// A boolean value indicating whether to disable ASLR or not.
///
/// @return
/// Zero if the for success, or an error code for failure.
//------------------------------------------------------------------
int
SetDisableASLR (bool enable);
+
+ //------------------------------------------------------------------
+ /// Sets the DetachOnError flag to \a enable for the process controlled by the stub.
+ ///
+ /// @param[in] enable
+ /// A boolean value indicating whether to detach on error or not.
+ ///
+ /// @return
+ /// Zero if the for success, or an error code for failure.
+ //------------------------------------------------------------------
+ int
+ SetDetachOnError (bool enable);
//------------------------------------------------------------------
/// Sets the working directory to \a path for a process that will
@@ -217,7 +233,7 @@ public:
/// directory for the platform process.
///
/// @param[in] path
- /// The path to a directory to use when launching our processs
+ /// The path to a directory to use when launching our process
///
/// @return
/// Zero if the for success, or an error code for failure.
@@ -279,6 +295,9 @@ public:
GetpPacketSupported (lldb::tid_t tid);
bool
+ GetxPacketSupported ();
+
+ bool
GetVAttachOrWaitSupported ();
bool
@@ -384,6 +403,9 @@ public:
SetCurrentThreadForRun (uint64_t tid);
bool
+ GetQXferAuxvReadSupported ();
+
+ bool
GetQXferLibrariesReadSupported ();
bool
@@ -491,7 +513,19 @@ public:
bool
RestoreRegisterState (lldb::tid_t tid, uint32_t save_id);
+
+ const char *
+ GetGDBServerProgramName();
+ uint32_t
+ GetGDBServerProgramVersion();
+
+ bool
+ AvoidGPackets(ProcessGDBRemote *process);
+
+ bool
+ GetThreadExtendedInfoSupported();
+
protected:
PacketResult
@@ -502,6 +536,9 @@ protected:
bool
GetCurrentProcessInfo ();
+ bool
+ GetGDBServerVersion();
+
//------------------------------------------------------------------
// Classes that inherit from GDBRemoteCommunicationClient can see and modify these
//------------------------------------------------------------------
@@ -515,7 +552,9 @@ protected:
lldb_private::LazyBool m_supports_vCont_s;
lldb_private::LazyBool m_supports_vCont_S;
lldb_private::LazyBool m_qHostInfo_is_valid;
+ lldb_private::LazyBool m_curr_pid_is_valid;
lldb_private::LazyBool m_qProcessInfo_is_valid;
+ lldb_private::LazyBool m_qGDBServerVersion_is_valid;
lldb_private::LazyBool m_supports_alloc_dealloc_memory;
lldb_private::LazyBool m_supports_memory_region_info;
lldb_private::LazyBool m_supports_watchpoint_support_info;
@@ -524,10 +563,14 @@ protected:
lldb_private::LazyBool m_attach_or_wait_reply;
lldb_private::LazyBool m_prepare_for_reg_writing_reply;
lldb_private::LazyBool m_supports_p;
+ lldb_private::LazyBool m_supports_x;
+ lldb_private::LazyBool m_avoid_g_packets;
lldb_private::LazyBool m_supports_QSaveRegisterState;
+ lldb_private::LazyBool m_supports_qXfer_auxv_read;
lldb_private::LazyBool m_supports_qXfer_libraries_read;
lldb_private::LazyBool m_supports_qXfer_libraries_svr4_read;
lldb_private::LazyBool m_supports_augmented_libraries_svr4_read;
+ lldb_private::LazyBool m_supports_jThreadExtendedInfo;
bool
m_supports_qProcessInfoPID:1,
@@ -543,7 +586,7 @@ protected:
m_supports_QEnvironment:1,
m_supports_QEnvironmentHexEncoded:1;
-
+ lldb::pid_t m_curr_pid;
lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations
lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for continue, step, etc
@@ -570,6 +613,8 @@ protected:
std::string m_os_build;
std::string m_os_kernel;
std::string m_hostname;
+ std::string m_gdb_server_name; // from reply to qGDBServerVersion, empty if qGDBServerVersion is not supported
+ uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if qGDBServerVersion is not supported
uint32_t m_default_packet_timeout;
uint64_t m_max_packet_size; // as returned by qSupported
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index df95542d2c0f..ffcdd169eb9f 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -9,24 +9,38 @@
#include <errno.h>
+#include "lldb/Host/Config.h"
+
#include "GDBRemoteCommunicationServer.h"
#include "lldb/Core/StreamGDBRemote.h"
// C Includes
// C++ Includes
+#include <cstring>
+#include <chrono>
+#include <thread>
+
// Other libraries and framework includes
#include "llvm/ADT/Triple.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Debug.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/File.h"
+#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Host/TimeValue.h"
+#include "lldb/Target/FileAction.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/NativeRegisterContext.h"
+#include "Host/common/NativeProcessProtocol.h"
+#include "Host/common/NativeThreadProtocol.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
@@ -37,6 +51,22 @@ using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
+// GDBRemote Errors
+//----------------------------------------------------------------------
+
+namespace
+{
+ enum GDBRemoteServerError
+ {
+ // Set to the first unused error number in literal form below
+ eErrorFirst = 29,
+ eErrorNoProcess = eErrorFirst,
+ eErrorResume,
+ eErrorExitStatus
+ };
+}
+
+//----------------------------------------------------------------------
// GDBRemoteCommunicationServer constructor
//----------------------------------------------------------------------
GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :
@@ -50,12 +80,28 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :
m_proc_infos (),
m_proc_infos_index (0),
m_port_map (),
- m_port_offset(0)
+ m_port_offset(0),
+ m_current_tid (LLDB_INVALID_THREAD_ID),
+ m_continue_tid (LLDB_INVALID_THREAD_ID),
+ m_debugged_process_mutex (Mutex::eMutexTypeRecursive),
+ m_debugged_process_sp (),
+ m_debugger_sp (),
+ m_stdio_communication ("process.stdio"),
+ m_exit_now (false),
+ m_inferior_prev_state (StateType::eStateInvalid),
+ m_thread_suffix_supported (false),
+ m_list_threads_in_stop_reply (false),
+ m_active_auxv_buffer_sp (),
+ m_saved_registers_mutex (),
+ m_saved_registers_map (),
+ m_next_saved_registers_id (1)
{
+ assert(is_platform && "must be lldb-platform if debugger is not specified");
}
GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform,
- const lldb::PlatformSP& platform_sp) :
+ const lldb::PlatformSP& platform_sp,
+ lldb::DebuggerSP &debugger_sp) :
GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform),
m_platform_sp (platform_sp),
m_async_thread (LLDB_INVALID_HOST_THREAD),
@@ -66,9 +112,24 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform,
m_proc_infos (),
m_proc_infos_index (0),
m_port_map (),
- m_port_offset(0)
+ m_port_offset(0),
+ m_current_tid (LLDB_INVALID_THREAD_ID),
+ m_continue_tid (LLDB_INVALID_THREAD_ID),
+ m_debugged_process_mutex (Mutex::eMutexTypeRecursive),
+ m_debugged_process_sp (),
+ m_debugger_sp (debugger_sp),
+ m_stdio_communication ("process.stdio"),
+ m_exit_now (false),
+ m_inferior_prev_state (StateType::eStateInvalid),
+ m_thread_suffix_supported (false),
+ m_list_threads_in_stop_reply (false),
+ m_active_auxv_buffer_sp (),
+ m_saved_registers_mutex (),
+ m_saved_registers_map (),
+ m_next_saved_registers_id (1)
{
assert(platform_sp);
+ assert((is_platform || debugger_sp) && "must specify non-NULL debugger_sp when lldb-gdbserver");
}
//----------------------------------------------------------------------
@@ -78,37 +139,14 @@ GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer()
{
}
-
-//void *
-//GDBRemoteCommunicationServer::AsyncThread (void *arg)
-//{
-// GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer*) arg;
-//
-// Log *log;// (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
-// if (log)
-// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID());
-//
-// StringExtractorGDBRemote packet;
-//
-// while ()
-// {
-// if (packet.
-// }
-//
-// if (log)
-// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID());
-//
-// process->m_async_thread = LLDB_INVALID_HOST_THREAD;
-// return NULL;
-//}
-//
-bool
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
Error &error,
bool &interrupt,
bool &quit)
{
StringExtractorGDBRemote packet;
+
PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec);
if (packet_result == PacketResult::Success)
{
@@ -124,11 +162,6 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
quit = true;
break;
- case StringExtractorGDBRemote::eServerPacketType_interrupt:
- error.SetErrorString("interrupt received");
- interrupt = true;
- break;
-
default:
case StringExtractorGDBRemote::eServerPacketType_unimplemented:
packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str());
@@ -164,6 +197,7 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
case StringExtractorGDBRemote::eServerPacketType_k:
packet_result = Handle_k (packet);
+ quit = true;
break;
case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
@@ -174,6 +208,10 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
packet_result = Handle_qGroupName (packet);
break;
+ case StringExtractorGDBRemote::eServerPacketType_qProcessInfo:
+ packet_result = Handle_qProcessInfo (packet);
+ break;
+
case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID:
packet_result = Handle_qProcessInfoPID (packet);
break;
@@ -202,6 +240,10 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
packet_result = Handle_QSetDisableASLR (packet);
break;
+ case StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError:
+ packet_result = Handle_QSetDetachOnError (packet);
+ break;
+
case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN:
packet_result = Handle_QSetSTDIN (packet);
break;
@@ -234,6 +276,26 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
packet_result = Handle_qPlatform_shell (packet);
break;
+ case StringExtractorGDBRemote::eServerPacketType_C:
+ packet_result = Handle_C (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_c:
+ packet_result = Handle_c (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_vCont:
+ packet_result = Handle_vCont (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_vCont_actions:
+ packet_result = Handle_vCont_actions (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_stop_reason: // ?
+ packet_result = Handle_stop_reason (packet);
+ break;
+
case StringExtractorGDBRemote::eServerPacketType_vFile_open:
packet_result = Handle_vFile_Open (packet);
break;
@@ -277,6 +339,96 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
case StringExtractorGDBRemote::eServerPacketType_vFile_unlink:
packet_result = Handle_vFile_unlink (packet);
break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qRegisterInfo:
+ packet_result = Handle_qRegisterInfo (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qfThreadInfo:
+ packet_result = Handle_qfThreadInfo (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qsThreadInfo:
+ packet_result = Handle_qsThreadInfo (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_p:
+ packet_result = Handle_p (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_P:
+ packet_result = Handle_P (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_H:
+ packet_result = Handle_H (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_m:
+ packet_result = Handle_m (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_M:
+ packet_result = Handle_M (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported:
+ packet_result = Handle_qMemoryRegionInfoSupported (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo:
+ packet_result = Handle_qMemoryRegionInfo (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_interrupt:
+ if (IsGdbServer ())
+ packet_result = Handle_interrupt (packet);
+ else
+ {
+ error.SetErrorString("interrupt received");
+ interrupt = true;
+ }
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_Z:
+ packet_result = Handle_Z (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_z:
+ packet_result = Handle_z (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_s:
+ packet_result = Handle_s (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qSupported:
+ packet_result = Handle_qSupported (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported:
+ packet_result = Handle_QThreadSuffixSupported (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply:
+ packet_result = Handle_QListThreadsInStopReply (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read:
+ packet_result = Handle_qXfer_auxv_read (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState:
+ packet_result = Handle_QSaveRegisterState (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState:
+ packet_result = Handle_QRestoreRegisterState (packet);
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_vAttach:
+ packet_result = Handle_vAttach (packet);
+ break;
}
}
else
@@ -291,7 +443,12 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
error.SetErrorString("timeout");
}
}
- return packet_result == PacketResult::Success;
+
+ // Check if anything occurred that would force us to want to exit.
+ if (m_exit_now)
+ quit = true;
+
+ return packet_result;
}
lldb_private::Error
@@ -314,6 +471,96 @@ GDBRemoteCommunicationServer::SetLaunchFlags (unsigned int launch_flags)
lldb_private::Error
GDBRemoteCommunicationServer::LaunchProcess ()
{
+ // FIXME This looks an awful lot like we could override this in
+ // derived classes, one for lldb-platform, the other for lldb-gdbserver.
+ if (IsGdbServer ())
+ return LaunchDebugServerProcess ();
+ else
+ return LaunchPlatformProcess ();
+}
+
+lldb_private::Error
+GDBRemoteCommunicationServer::LaunchDebugServerProcess ()
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_process_launch_info.GetArguments ().GetArgumentCount ())
+ return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__);
+
+ lldb_private::Error error;
+ {
+ Mutex::Locker locker (m_debugged_process_mutex);
+ assert (!m_debugged_process_sp && "lldb-gdbserver creating debugged process but one already exists");
+ error = m_platform_sp->LaunchNativeProcess (
+ m_process_launch_info,
+ *this,
+ m_debugged_process_sp);
+ }
+
+ if (!error.Success ())
+ {
+ fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0));
+ return error;
+ }
+
+ // Setup stdout/stderr mapping from inferior.
+ auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor ();
+ if (terminal_fd >= 0)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServer::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd);
+ error = SetSTDIOFileDescriptor (terminal_fd);
+ if (error.Fail ())
+ return error;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServer::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd);
+ }
+
+ printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID ());
+
+ // Add to list of spawned processes.
+ lldb::pid_t pid;
+ if ((pid = m_process_launch_info.GetProcessID ()) != LLDB_INVALID_PROCESS_ID)
+ {
+ // add to spawned pids
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ // On an lldb-gdbserver, we would expect there to be only one.
+ assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed");
+ m_spawned_pids.insert (pid);
+ }
+ }
+
+ if (error.Success ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s beginning check to wait for launched application to hit first stop", __FUNCTION__);
+
+ int iteration = 0;
+ // Wait for the process to hit its first stop state.
+ while (!StateIsStoppedState (m_debugged_process_sp->GetState (), false))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s waiting for launched process to hit first stop (%d)...", __FUNCTION__, iteration++);
+
+ // FIXME use a finer granularity.
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s launched application has hit first stop", __FUNCTION__);
+
+ }
+
+ return error;
+}
+
+lldb_private::Error
+GDBRemoteCommunicationServer::LaunchPlatformProcess ()
+{
if (!m_process_launch_info.GetArguments ().GetArgumentCount ())
return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__);
@@ -337,13 +584,571 @@ GDBRemoteCommunicationServer::LaunchProcess ()
lldb::pid_t pid;
if ( (pid = m_process_launch_info.GetProcessID()) != LLDB_INVALID_PROCESS_ID )
{
+ // add to spawned pids
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ m_spawned_pids.insert(pid);
+ }
+ }
+
+ return error;
+}
+
+lldb_private::Error
+GDBRemoteCommunicationServer::AttachToProcess (lldb::pid_t pid)
+{
+ Error error;
+
+ if (!IsGdbServer ())
+ {
+ error.SetErrorString("cannot AttachToProcess () unless process is lldb-gdbserver");
+ return error;
+ }
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64, __FUNCTION__, pid);
+
+ // Scope for mutex locker.
+ {
+ // Before we try to attach, make sure we aren't already monitoring something else.
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (!m_spawned_pids.empty ())
+ {
+ error.SetErrorStringWithFormat ("cannot attach to a process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", pid, *m_spawned_pids.begin());
+ return error;
+ }
+
+ // Try to attach.
+ error = m_platform_sp->AttachNativeProcess (pid, *this, m_debugged_process_sp);
+ if (!error.Success ())
+ {
+ fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ());
+ return error;
+ }
+
+ // Setup stdout/stderr mapping from inferior.
+ auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor ();
+ if (terminal_fd >= 0)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServer::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd);
+ error = SetSTDIOFileDescriptor (terminal_fd);
+ if (error.Fail ())
+ return error;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServer::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd);
+ }
+
+ printf ("Attached to process %" PRIu64 "...\n", pid);
+
+ // Add to list of spawned processes.
+ assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed");
+ m_spawned_pids.insert (pid);
+
+ return error;
+ }
+}
+
+void
+GDBRemoteCommunicationServer::InitializeDelegate (lldb_private::NativeProcessProtocol *process)
+{
+ assert (process && "process cannot be NULL");
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s called with NativeProcessProtocol pid %" PRIu64 ", current state: %s",
+ __FUNCTION__,
+ process->GetID (),
+ StateAsCString (process->GetState ()));
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendWResponse (lldb_private::NativeProcessProtocol *process)
+{
+ assert (process && "process cannot be NULL");
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // send W notification
+ ExitType exit_type = ExitType::eExitTypeInvalid;
+ int return_code = 0;
+ std::string exit_description;
+
+ const bool got_exit_info = process->GetExitStatus (&exit_type, &return_code, exit_description);
+ if (!got_exit_info)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", failed to retrieve process exit status", __FUNCTION__, process->GetID ());
+
+ StreamGDBRemote response;
+ response.PutChar ('E');
+ response.PutHex8 (GDBRemoteServerError::eErrorExitStatus);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", returning exit type %d, return code %d [%s]", __FUNCTION__, process->GetID (), exit_type, return_code, exit_description.c_str ());
+
+ StreamGDBRemote response;
+
+ char return_type_code;
+ switch (exit_type)
+ {
+ case ExitType::eExitTypeExit: return_type_code = 'W'; break;
+ case ExitType::eExitTypeSignal: return_type_code = 'X'; break;
+ case ExitType::eExitTypeStop: return_type_code = 'S'; break;
+
+ case ExitType::eExitTypeInvalid:
+ default: return_type_code = 'E'; break;
+ }
+ response.PutChar (return_type_code);
+
+ // POSIX exit status limited to unsigned 8 bits.
+ response.PutHex8 (return_code);
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+}
+
+static void
+AppendHexValue (StreamString &response, const uint8_t* buf, uint32_t buf_size, bool swap)
+{
+ int64_t i;
+ if (swap)
+ {
+ for (i = buf_size-1; i >= 0; i--)
+ response.PutHex8 (buf[i]);
+ }
+ else
+ {
+ for (i = 0; i < buf_size; i++)
+ response.PutHex8 (buf[i]);
+ }
+}
+
+static void
+WriteRegisterValueInHexFixedWidth (StreamString &response,
+ NativeRegisterContextSP &reg_ctx_sp,
+ const RegisterInfo &reg_info,
+ const RegisterValue *reg_value_p)
+{
+ RegisterValue reg_value;
+ if (!reg_value_p)
+ {
+ Error error = reg_ctx_sp->ReadRegister (&reg_info, reg_value);
+ if (error.Success ())
+ reg_value_p = &reg_value;
+ // else log.
+ }
+
+ if (reg_value_p)
+ {
+ AppendHexValue (response, (const uint8_t*) reg_value_p->GetBytes (), reg_value_p->GetByteSize (), false);
+ }
+ else
+ {
+ // Zero-out any unreadable values.
+ if (reg_info.byte_size > 0)
+ {
+ std::basic_string<uint8_t> zeros(reg_info.byte_size, '\0');
+ AppendHexValue (response, zeros.data(), zeros.size(), false);
+ }
+ }
+}
+
+// WriteGdbRegnumWithFixedWidthHexRegisterValue (response, reg_ctx_sp, *reg_info_p, reg_value);
+
+
+static void
+WriteGdbRegnumWithFixedWidthHexRegisterValue (StreamString &response,
+ NativeRegisterContextSP &reg_ctx_sp,
+ const RegisterInfo &reg_info,
+ const RegisterValue &reg_value)
+{
+ // Output the register number as 'NN:VVVVVVVV;' where NN is a 2 bytes HEX
+ // gdb register number, and VVVVVVVV is the correct number of hex bytes
+ // as ASCII for the register value.
+ if (reg_info.kinds[eRegisterKindGDB] == LLDB_INVALID_REGNUM)
+ return;
+
+ response.Printf ("%.02x:", reg_info.kinds[eRegisterKindGDB]);
+ WriteRegisterValueInHexFixedWidth (response, reg_ctx_sp, reg_info, &reg_value);
+ response.PutChar (';');
+}
+
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendStopReplyPacketForThread (lldb::tid_t tid)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+
+ // Ensure we're llgs.
+ if (!IsGdbServer ())
+ {
+ // Only supported on llgs
+ return SendUnimplementedResponse ("");
+ }
+
+ // Ensure we have a debugged process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse (50);
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s preparing packet for pid %" PRIu64 " tid %" PRIu64,
+ __FUNCTION__, m_debugged_process_sp->GetID (), tid);
+
+ // Ensure we can get info on the given thread.
+ NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid));
+ if (!thread_sp)
+ return SendErrorResponse (51);
+
+ // Grab the reason this thread stopped.
+ struct ThreadStopInfo tid_stop_info;
+ if (!thread_sp->GetStopReason (tid_stop_info))
+ return SendErrorResponse (52);
+
+ const bool did_exec = tid_stop_info.reason == eStopReasonExec;
+ // FIXME implement register handling for exec'd inferiors.
+ // if (did_exec)
+ // {
+ // const bool force = true;
+ // InitializeRegisters(force);
+ // }
+
+ StreamString response;
+ // Output the T packet with the thread
+ response.PutChar ('T');
+ int signum = tid_stop_info.details.signal.signo;
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64,
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ tid,
+ signum,
+ tid_stop_info.reason,
+ tid_stop_info.details.exception.type);
+ }
+
+ switch (tid_stop_info.reason)
+ {
+ case eStopReasonSignal:
+ case eStopReasonException:
+ signum = thread_sp->TranslateStopInfoToGdbSignal (tid_stop_info);
+ break;
+ default:
+ signum = 0;
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " has stop reason %d, using signo = 0 in stop reply response",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ tid,
+ tid_stop_info.reason);
+ }
+ break;
+ }
+
+ // Print the signal number.
+ response.PutHex8 (signum & 0xff);
+
+ // Include the tid.
+ response.Printf ("thread:%" PRIx64 ";", tid);
+
+ // Include the thread name if there is one.
+ const char *thread_name = thread_sp->GetName ();
+ if (thread_name && thread_name[0])
+ {
+ size_t thread_name_len = strlen(thread_name);
+
+ if (::strcspn (thread_name, "$#+-;:") == thread_name_len)
+ {
+ response.PutCString ("name:");
+ response.PutCString (thread_name);
+ }
+ else
+ {
+ // The thread name contains special chars, send as hex bytes.
+ response.PutCString ("hexname:");
+ response.PutCStringAsRawHex8 (thread_name);
+ }
+ response.PutChar (';');
+ }
+
+ // FIXME look for analog
+ // thread_identifier_info_data_t thread_ident_info;
+ // if (DNBThreadGetIdentifierInfo (pid, tid, &thread_ident_info))
+ // {
+ // if (thread_ident_info.dispatch_qaddr != 0)
+ // ostrm << std::hex << "qaddr:" << thread_ident_info.dispatch_qaddr << ';';
+ // }
+
+ // If a 'QListThreadsInStopReply' was sent to enable this feature, we
+ // will send all thread IDs back in the "threads" key whose value is
+ // a list of hex thread IDs separated by commas:
+ // "threads:10a,10b,10c;"
+ // This will save the debugger from having to send a pair of qfThreadInfo
+ // and qsThreadInfo packets, but it also might take a lot of room in the
+ // stop reply packet, so it must be enabled only on systems where there
+ // are no limits on packet lengths.
+ if (m_list_threads_in_stop_reply)
+ {
+ response.PutCString ("threads:");
+
+ uint32_t thread_index = 0;
+ NativeThreadProtocolSP listed_thread_sp;
+ for (listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); listed_thread_sp; ++thread_index, listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index))
+ {
+ if (thread_index > 0)
+ response.PutChar (',');
+ response.Printf ("%" PRIx64, listed_thread_sp->GetID ());
+ }
+ response.PutChar (';');
+ }
+
+ //
+ // Expedite registers.
+ //
+
+ // Grab the register context.
+ NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext ();
+ if (reg_ctx_sp)
+ {
+ // Expedite all registers in the first register set (i.e. should be GPRs) that are not contained in other registers.
+ const RegisterSet *reg_set_p;
+ if (reg_ctx_sp->GetRegisterSetCount () > 0 && ((reg_set_p = reg_ctx_sp->GetRegisterSet (0)) != nullptr))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s expediting registers from set '%s' (registers set count: %zu)", __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", reg_set_p->num_registers);
+
+ for (const uint32_t *reg_num_p = reg_set_p->registers; *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p)
+ {
+ const RegisterInfo *const reg_info_p = reg_ctx_sp->GetRegisterInfoAtIndex (*reg_num_p);
+ if (reg_info_p == nullptr)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to get register info for register set '%s', register index %" PRIu32, __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", *reg_num_p);
+ }
+ else if (reg_info_p->value_regs == nullptr)
+ {
+ // Only expediate registers that are not contained in other registers.
+ RegisterValue reg_value;
+ Error error = reg_ctx_sp->ReadRegister (reg_info_p, reg_value);
+ if (error.Success ())
+ WriteGdbRegnumWithFixedWidthHexRegisterValue (response, reg_ctx_sp, *reg_info_p, reg_value);
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, reg_info_p->name ? reg_info_p->name : "<unnamed-register>", *reg_num_p, error.AsCString ());
+
+ }
+ }
+ }
+ }
+ }
+
+ if (did_exec)
+ {
+ response.PutCString ("reason:exec;");
+ }
+ else if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type)
+ {
+ response.PutCString ("metype:");
+ response.PutHex64 (tid_stop_info.details.exception.type);
+ response.PutCString (";mecount:");
+ response.PutHex32 (tid_stop_info.details.exception.data_count);
+ response.PutChar (';');
+
+ for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i)
+ {
+ response.PutCString ("medata:");
+ response.PutHex64 (tid_stop_info.details.exception.data[i]);
+ response.PutChar (';');
+ }
+ }
+
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+void
+GDBRemoteCommunicationServer::HandleInferiorState_Exited (lldb_private::NativeProcessProtocol *process)
+{
+ assert (process && "process cannot be NULL");
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__);
+
+ // Send the exit result, and don't flush output.
+ // Note: flushing output here would join the inferior stdio reflection thread, which
+ // would gunk up the waitpid monitor thread that is calling this.
+ PacketResult result = SendStopReasonForState (StateType::eStateExited, false);
+ if (result != PacketResult::Success)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ());
+ }
+
+ // Remove the process from the list of spawned pids.
+ {
Mutex::Locker locker (m_spawned_pids_mutex);
- m_spawned_pids.insert(pid);
+ if (m_spawned_pids.erase (process->GetID ()) < 1)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to remove PID %" PRIu64 " from the spawned pids list", __FUNCTION__, process->GetID ());
+
+ }
}
+ // FIXME can't do this yet - since process state propagation is currently
+ // synchronous, it is running off the NativeProcessProtocol's innards and
+ // will tear down the NPP while it still has code to execute.
+#if 0
+ // Clear the NativeProcessProtocol pointer.
+ {
+ Mutex::Locker locker (m_debugged_process_mutex);
+ m_debugged_process_sp.reset();
+ }
+#endif
+
+ // Close the pipe to the inferior terminal i/o if we launched it
+ // and set one up. Otherwise, 'k' and its flush of stdio could
+ // end up waiting on a thread join that will never end. Consider
+ // adding a timeout to the connection thread join call so we
+ // can avoid that scenario altogether.
+ MaybeCloseInferiorTerminalConnection ();
+
+ // We are ready to exit the debug monitor.
+ m_exit_now = true;
+}
+
+void
+GDBRemoteCommunicationServer::HandleInferiorState_Stopped (lldb_private::NativeProcessProtocol *process)
+{
+ assert (process && "process cannot be NULL");
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__);
+
+ // Send the stop reason unless this is the stop after the
+ // launch or attach.
+ switch (m_inferior_prev_state)
+ {
+ case eStateLaunching:
+ case eStateAttaching:
+ // Don't send anything per debugserver behavior.
+ break;
+ default:
+ // In all other cases, send the stop reason.
+ PacketResult result = SendStopReasonForState (StateType::eStateStopped, false);
+ if (result != PacketResult::Success)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ());
+ }
+ break;
+ }
+}
+
+void
+GDBRemoteCommunicationServer::ProcessStateChanged (lldb_private::NativeProcessProtocol *process, lldb::StateType state)
+{
+ assert (process && "process cannot be NULL");
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s called with NativeProcessProtocol pid %" PRIu64 ", state: %s",
+ __FUNCTION__,
+ process->GetID (),
+ StateAsCString (state));
+ }
+
+ switch (state)
+ {
+ case StateType::eStateExited:
+ HandleInferiorState_Exited (process);
+ break;
+
+ case StateType::eStateStopped:
+ HandleInferiorState_Stopped (process);
+ break;
+
+ default:
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s didn't handle state change for pid %" PRIu64 ", new state: %s",
+ __FUNCTION__,
+ process->GetID (),
+ StateAsCString (state));
+ }
+ break;
+ }
+
+ // Remember the previous state reported to us.
+ m_inferior_prev_state = state;
+}
+
+void
+GDBRemoteCommunicationServer::DidExec (NativeProcessProtocol *process)
+{
+ ClearProcessSpecificData ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendONotification (const char *buffer, uint32_t len)
+{
+ if ((buffer == nullptr) || (len == 0))
+ {
+ // Nothing to send.
+ return PacketResult::Success;
+ }
+
+ StreamString response;
+ response.PutChar ('O');
+ response.PutBytesAsRawHex8 (buffer, len);
+
+ return SendPacketNoLock (response.GetData (), response.GetSize ());
+}
+
+lldb_private::Error
+GDBRemoteCommunicationServer::SetSTDIOFileDescriptor (int fd)
+{
+ Error error;
+
+ // Set up the Read Thread for reading/handling process I/O
+ std::unique_ptr<ConnectionFileDescriptor> conn_up (new ConnectionFileDescriptor (fd, true));
+ if (!conn_up)
+ {
+ error.SetErrorString ("failed to create ConnectionFileDescriptor");
+ return error;
+ }
+
+ m_stdio_communication.SetConnection (conn_up.release());
+ if (!m_stdio_communication.IsConnected ())
+ {
+ error.SetErrorString ("failed to set connection for inferior I/O communication");
+ return error;
+ }
+
+ m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this);
+ m_stdio_communication.StartReadThread();
+
return error;
}
+void
+GDBRemoteCommunicationServer::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len)
+{
+ GDBRemoteCommunicationServer *server = reinterpret_cast<GDBRemoteCommunicationServer*> (baton);
+ static_cast<void> (server->SendONotification (static_cast<const char *>(src), src_len));
+}
+
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *)
{
@@ -351,6 +1156,7 @@ GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *)
return SendPacketNoLock ("", 0);
}
+
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err)
{
@@ -360,6 +1166,14 @@ GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err)
return SendPacketNoLock (packet, packet_len);
}
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendIllFormedResponse (const StringExtractorGDBRemote &failed_packet, const char *message)
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", __FUNCTION__, failed_packet.GetStringRef ().c_str (), message ? message : "");
+ return SendErrorResponse (0x03);
+}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendOKResponse ()
@@ -380,10 +1194,10 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet
// $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
- ArchSpec host_arch (Host::GetArchitecture ());
+ ArchSpec host_arch(HostInfo::GetArchitecture());
const llvm::Triple &host_triple = host_arch.GetTriple();
response.PutCString("triple:");
- response.PutCStringAsRawHex8(host_triple.getTriple().c_str());
+ response.PutCString(host_triple.getTriple().c_str());
response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize());
const char* distribution_id = host_arch.GetDistributionId ().AsCString ();
@@ -394,6 +1208,8 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet
response.PutCString(";");
}
+ // Only send out MachO info when lldb-platform/llgs is running on a MachO host.
+#if defined(__APPLE__)
uint32_t cpu = host_arch.GetMachOCPUType();
uint32_t sub = host_arch.GetMachOCPUSubType();
if (cpu != LLDB_INVALID_CPUTYPE)
@@ -405,6 +1221,9 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet
response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes.
else
response.Printf("watchpoint_exceptions_received:after;");
+#else
+ response.Printf("watchpoint_exceptions_received:after;");
+#endif
switch (lldb::endian::InlHostByteOrder())
{
@@ -417,7 +1236,7 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet
uint32_t major = UINT32_MAX;
uint32_t minor = UINT32_MAX;
uint32_t update = UINT32_MAX;
- if (Host::GetOSVersion (major, minor, update))
+ if (HostInfo::GetOSVersion(major, minor, update))
{
if (major != UINT32_MAX)
{
@@ -433,39 +1252,41 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet
}
std::string s;
- if (Host::GetOSBuildString (s))
+#if !defined(__linux__)
+ if (HostInfo::GetOSBuildString(s))
{
response.PutCString ("os_build:");
response.PutCStringAsRawHex8(s.c_str());
response.PutChar(';');
}
- if (Host::GetOSKernelDescription (s))
+ if (HostInfo::GetOSKernelDescription(s))
{
response.PutCString ("os_kernel:");
response.PutCStringAsRawHex8(s.c_str());
response.PutChar(';');
}
+#endif
+
#if defined(__APPLE__)
-#if defined(__arm__)
+#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
// For iOS devices, we are connected through a USB Mux so we never pretend
// to actually have a hostname as far as the remote lldb that is connecting
// to this lldb-platform is concerned
response.PutCString ("hostname:");
- response.PutCStringAsRawHex8("localhost");
+ response.PutCStringAsRawHex8("127.0.0.1");
response.PutChar(';');
-#else // #if defined(__arm__)
- if (Host::GetHostname (s))
+#else // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
+ if (HostInfo::GetHostname(s))
{
response.PutCString ("hostname:");
response.PutCStringAsRawHex8(s.c_str());
response.PutChar(';');
}
-
-#endif // #if defined(__arm__)
+#endif // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
#else // #if defined(__APPLE__)
- if (Host::GetHostname (s))
+ if (HostInfo::GetHostname(s))
{
response.PutCString ("hostname:");
response.PutCStringAsRawHex8(s.c_str());
@@ -494,11 +1315,105 @@ CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &r
{
const llvm::Triple &proc_triple = proc_arch.GetTriple();
response.PutCString("triple:");
- response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
+ response.PutCString(proc_triple.getTriple().c_str());
response.PutChar(';');
}
}
+static void
+CreateProcessInfoResponse_DebugServerStyle (const ProcessInstanceInfo &proc_info, StreamString &response)
+{
+ response.Printf ("pid:%" PRIx64 ";parent-pid:%" PRIx64 ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;",
+ proc_info.GetProcessID(),
+ proc_info.GetParentProcessID(),
+ proc_info.GetUserID(),
+ proc_info.GetGroupID(),
+ proc_info.GetEffectiveUserID(),
+ proc_info.GetEffectiveGroupID());
+
+ const ArchSpec &proc_arch = proc_info.GetArchitecture();
+ if (proc_arch.IsValid())
+ {
+ const llvm::Triple &proc_triple = proc_arch.GetTriple();
+#if defined(__APPLE__)
+ // We'll send cputype/cpusubtype.
+ const uint32_t cpu_type = proc_arch.GetMachOCPUType();
+ if (cpu_type != 0)
+ response.Printf ("cputype:%" PRIx32 ";", cpu_type);
+
+ const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType();
+ if (cpu_subtype != 0)
+ response.Printf ("cpusubtype:%" PRIx32 ";", cpu_subtype);
+
+
+ const std::string vendor = proc_triple.getVendorName ();
+ if (!vendor.empty ())
+ response.Printf ("vendor:%s;", vendor.c_str ());
+#else
+ // We'll send the triple.
+ response.Printf ("triple:%s;", proc_triple.getTriple().c_str ());
+#endif
+ std::string ostype = proc_triple.getOSName ();
+ // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64.
+ if (proc_triple.getVendor () == llvm::Triple::Apple)
+ {
+ switch (proc_triple.getArch ())
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
+ ostype = "ios";
+ break;
+ default:
+ // No change.
+ break;
+ }
+ }
+ response.Printf ("ostype:%s;", ostype.c_str ());
+
+
+ switch (proc_arch.GetByteOrder ())
+ {
+ case lldb::eByteOrderLittle: response.PutCString ("endian:little;"); break;
+ case lldb::eByteOrderBig: response.PutCString ("endian:big;"); break;
+ case lldb::eByteOrderPDP: response.PutCString ("endian:pdp;"); break;
+ default:
+ // Nothing.
+ break;
+ }
+
+ if (proc_triple.isArch64Bit ())
+ response.PutCString ("ptrsize:8;");
+ else if (proc_triple.isArch32Bit ())
+ response.PutCString ("ptrsize:4;");
+ else if (proc_triple.isArch16Bit ())
+ response.PutCString ("ptrsize:2;");
+ }
+
+}
+
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qProcessInfo (StringExtractorGDBRemote &packet)
+{
+ // Only the gdb server handles this.
+ if (!IsGdbServer ())
+ return SendUnimplementedResponse (packet.GetStringRef ().c_str ());
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse (68);
+
+ ProcessInstanceInfo proc_info;
+ if (Host::GetProcessInfo (m_debugged_process_sp->GetID (), proc_info))
+ {
+ StreamString response;
+ CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
+ return SendPacketNoLock (response.GetData (), response.GetSize ());
+ }
+
+ return SendErrorResponse (1);
+}
+
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet)
{
@@ -635,19 +1550,21 @@ GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &pa
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet)
{
+#if !defined(LLDB_DISABLE_POSIX)
// Packet format: "qUserName:%i" where %i is the uid
packet.SetFilePos(::strlen ("qUserName:"));
uint32_t uid = packet.GetU32 (UINT32_MAX);
if (uid != UINT32_MAX)
{
std::string name;
- if (Host::GetUserName (uid, name))
+ if (HostInfo::LookupUserName(uid, name))
{
StreamString response;
response.PutCStringAsRawHex8 (name.c_str());
return SendPacketNoLock (response.GetData(), response.GetSize());
}
}
+#endif
return SendErrorResponse (5);
}
@@ -655,19 +1572,21 @@ GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet)
{
+#if !defined(LLDB_DISABLE_POSIX)
// Packet format: "qGroupName:%i" where %i is the gid
packet.SetFilePos(::strlen ("qGroupName:"));
uint32_t gid = packet.GetU32 (UINT32_MAX);
if (gid != UINT32_MAX)
{
std::string name;
- if (Host::GetGroupName (gid, name))
+ if (HostInfo::LookupGroupName(gid, name))
{
StreamString response;
response.PutCStringAsRawHex8 (name.c_str());
return SendPacketNoLock (response.GetData(), response.GetSize());
}
}
+#endif
return SendErrorResponse (6);
}
@@ -708,27 +1627,6 @@ GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packe
return SendErrorResponse (7);
}
-
-static void *
-AcceptPortFromInferior (void *arg)
-{
- const char *connect_url = (const char *)arg;
- ConnectionFileDescriptor file_conn;
- Error error;
- if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess)
- {
- char pid_str[256];
- ::memset (pid_str, 0, sizeof(pid_str));
- ConnectionStatus status;
- const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), 0, status, NULL);
- if (pid_str_len > 0)
- {
- int pid = atoi (pid_str);
- return (void *)(intptr_t)pid;
- }
- }
- return NULL;
-}
//
//static bool
//WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
@@ -772,6 +1670,9 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
// separated hex encoded argument value list, but we will stay true to the
// documented version of the 'A' packet here...
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ int actual_arg_index = 0;
+
packet.SetFilePos(1); // Skip the 'A'
bool success = true;
while (success && packet.GetBytesLeft() > 0)
@@ -788,7 +1689,7 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
success = false;
else
{
- // Decode the argument index. We ignore this really becuase
+ // Decode the argument index. We ignore this really because
// who would really send down the arguments in a random order???
const uint32_t arg_idx = packet.GetU32(UINT32_MAX);
if (arg_idx == UINT32_MAX)
@@ -804,11 +1705,11 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
// back into a UTF8 string and make sure the length
// matches the one supplied in the packet
std::string arg;
- if (packet.GetHexByteString(arg) != (arg_len / 2))
+ if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2))
success = false;
else
{
- // If there are any bytes lft
+ // If there are any bytes left
if (packet.GetBytesLeft())
{
if (packet.GetChar() != ',')
@@ -820,6 +1721,9 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
if (arg_idx == 0)
m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false);
m_process_launch_info.GetArguments().AppendArgument(arg.c_str());
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str ());
+ ++actual_arg_index;
}
}
}
@@ -830,15 +1734,20 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
if (success)
{
- // FIXME: remove linux restriction once eLaunchFlagDebug is supported
-#if !defined (__linux__)
- m_process_launch_info.GetFlags().Set (eLaunchFlagDebug);
-#endif
m_process_launch_error = LaunchProcess ();
if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
{
return SendOKResponse ();
}
+ else
+ {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("GDBRemoteCommunicationServer::%s failed to launch exe: %s",
+ __FUNCTION__,
+ m_process_launch_error.AsCString());
+
+ }
}
return SendErrorResponse (8);
}
@@ -846,22 +1755,51 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)
{
- lldb::pid_t pid = m_process_launch_info.GetProcessID();
StreamString response;
- response.Printf("QC%" PRIx64, pid);
- if (m_is_platform)
+
+ if (IsGdbServer ())
+ {
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse (68);
+
+ // Make sure we set the current thread so g and p packets return
+ // the data the gdb will expect.
+ lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID ();
+ SetCurrentThreadID (tid);
+
+ NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread ();
+ if (!thread_sp)
+ return SendErrorResponse (69);
+
+ response.Printf ("QC%" PRIx64, thread_sp->GetID ());
+ }
+ else
{
- // If we launch a process and this GDB server is acting as a platform,
- // then we need to clear the process launch state so we can start
- // launching another process. In order to launch a process a bunch or
- // packets need to be sent: environment packets, working directory,
- // disable ASLR, and many more settings. When we launch a process we
- // then need to know when to clear this information. Currently we are
- // selecting the 'qC' packet as that packet which seems to make the most
- // sense.
- if (pid != LLDB_INVALID_PROCESS_ID)
+ // NOTE: lldb should now be using qProcessInfo for process IDs. This path here
+ // should not be used. It is reporting process id instead of thread id. The
+ // correct answer doesn't seem to make much sense for lldb-platform.
+ // CONSIDER: flip to "unsupported".
+ lldb::pid_t pid = m_process_launch_info.GetProcessID();
+ response.Printf("QC%" PRIx64, pid);
+
+ // this should always be platform here
+ assert (m_is_platform && "this code path should only be traversed for lldb-platform");
+
+ if (m_is_platform)
{
- m_process_launch_info.Clear();
+ // If we launch a process and this GDB server is acting as a platform,
+ // then we need to clear the process launch state so we can start
+ // launching another process. In order to launch a process a bunch or
+ // packets need to be sent: environment packets, working directory,
+ // disable ASLR, and many more settings. When we launch a process we
+ // then need to know when to clear this information. Currently we are
+ // selecting the 'qC' packet as that packet which seems to make the most
+ // sense.
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ m_process_launch_info.Clear();
+ }
}
}
return SendPacketNoLock (response.GetData(), response.GetSize());
@@ -912,17 +1850,21 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote
#ifdef _WIN32
return SendErrorResponse(9);
#else
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+
// Spawn a local debugserver as a platform so we can then attach or launch
// a process...
if (m_is_platform)
{
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s() called", __FUNCTION__);
+
// Sleep and wait a bit for debugserver to start to listen...
ConnectionFileDescriptor file_conn;
- Error error;
std::string hostname;
// TODO: /tmp/ should not be hardcoded. User might want to override /tmp
- // with the TMPDIR environnement variable
+ // with the TMPDIR environment variable
packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
std::string name;
std::string value;
@@ -940,53 +1882,57 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote
// Spawn a new thread to accept the port that gets bound after
// binding to port 0 (zero).
- if (error.Success())
- {
- // Spawn a debugserver and try to get the port it listens to.
- ProcessLaunchInfo debugserver_launch_info;
- if (hostname.empty())
- hostname = "localhost";
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
- if (log)
- log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port);
+ // Spawn a debugserver and try to get the port it listens to.
+ ProcessLaunchInfo debugserver_launch_info;
+ if (hostname.empty())
+ hostname = "127.0.0.1";
+ if (log)
+ log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port);
- debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
-
- error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(),
- port,
- debugserver_launch_info,
- port);
+ debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
- lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
+ Error error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(),
+ port,
+ debugserver_launch_info,
+ port);
+ lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
- if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
- {
- Mutex::Locker locker (m_spawned_pids_mutex);
- m_spawned_pids.insert(debugserver_pid);
- if (port > 0)
- AssociatePortWithProcess(port, debugserver_pid);
- }
- else
- {
- if (port > 0)
- FreePort (port);
- }
- if (error.Success())
- {
- char response[256];
- const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
- assert (response_len < sizeof(response));
- PacketResult packet_result = SendPacketNoLock (response, response_len);
+ if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ m_spawned_pids.insert(debugserver_pid);
+ if (port > 0)
+ AssociatePortWithProcess(port, debugserver_pid);
+ }
+ else
+ {
+ if (port > 0)
+ FreePort (port);
+ }
- if (packet_result != PacketResult::Success)
- {
- if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
- ::kill (debugserver_pid, SIGINT);
- }
- return packet_result;
+ if (error.Success())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid);
+
+ char response[256];
+ const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
+ assert (response_len < (int)sizeof(response));
+ PacketResult packet_result = SendPacketNoLock (response, response_len);
+
+ if (packet_result != PacketResult::Success)
+ {
+ if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ ::kill (debugserver_pid, SIGINT);
}
+ return packet_result;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ());
}
}
return SendErrorResponse (9);
@@ -1027,7 +1973,7 @@ GDBRemoteCommunicationServer::KillSpawnedProcess (lldb::pid_t pid)
return true;
}
- // the launched process still lives. Now try killling it again,
+ // the launched process still lives. Now try killing it again,
// this time with an unblockable signal.
Host::Kill (pid, SIGKILL);
@@ -1107,8 +2053,11 @@ GDBRemoteCommunicationServer::Handle_k (StringExtractorGDBRemote &packet)
}
}
- // TODO figure out how to shut down gracefully at this point
- return SendOKResponse ();
+ FlushInferiorOutput ();
+
+ // No OK response for kill packet.
+ // return SendOKResponse ();
+ return PacketResult::Success;
}
GDBRemoteCommunication::PacketResult
@@ -1223,7 +2172,7 @@ GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)
{
packet.SetFilePos(::strlen ("QSetSTDIN:"));
- ProcessLaunchInfo::FileAction file_action;
+ FileAction file_action;
std::string path;
packet.GetHexByteString(path);
const bool read = false;
@@ -1240,7 +2189,7 @@ GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet)
{
packet.SetFilePos(::strlen ("QSetSTDOUT:"));
- ProcessLaunchInfo::FileAction file_action;
+ FileAction file_action;
std::string path;
packet.GetHexByteString(path);
const bool read = true;
@@ -1257,7 +2206,7 @@ GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet)
{
packet.SetFilePos(::strlen ("QSetSTDERR:"));
- ProcessLaunchInfo::FileAction file_action;
+ FileAction file_action;
std::string path;
packet.GetHexByteString(path);
const bool read = true;
@@ -1271,6 +2220,288 @@ GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packe
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_C (StringExtractorGDBRemote &packet)
+{
+ if (!IsGdbServer ())
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__);
+
+ // Ensure we have a native process.
+ if (!m_debugged_process_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__);
+ return SendErrorResponse (0x36);
+ }
+
+ // Pull out the signal number.
+ packet.SetFilePos (::strlen ("C"));
+ if (packet.GetBytesLeft () < 1)
+ {
+ // Shouldn't be using a C without a signal.
+ return SendIllFormedResponse (packet, "C packet specified without signal.");
+ }
+ const uint32_t signo = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (signo == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse (packet, "failed to parse signal number");
+
+ // Handle optional continue address.
+ if (packet.GetBytesLeft () > 0)
+ {
+ // FIXME add continue at address support for $C{signo}[;{continue-address}].
+ if (*packet.Peek () == ';')
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+ else
+ return SendIllFormedResponse (packet, "unexpected content after $C{signal-number}");
+ }
+
+ lldb_private::ResumeActionList resume_actions (StateType::eStateRunning, 0);
+ Error error;
+
+ // We have two branches: what to do if a continue thread is specified (in which case we target
+ // sending the signal to that thread), or when we don't have a continue thread set (in which
+ // case we send a signal to the process).
+
+ // TODO discuss with Greg Clayton, make sure this makes sense.
+
+ lldb::tid_t signal_tid = GetContinueThreadID ();
+ if (signal_tid != LLDB_INVALID_THREAD_ID)
+ {
+ // The resume action for the continue thread (or all threads if a continue thread is not set).
+ lldb_private::ResumeAction action = { GetContinueThreadID (), StateType::eStateRunning, static_cast<int> (signo) };
+
+ // Add the action for the continue thread (or all threads when the continue thread isn't present).
+ resume_actions.Append (action);
+ }
+ else
+ {
+ // Send the signal to the process since we weren't targeting a specific continue thread with the signal.
+ error = m_debugged_process_sp->Signal (signo);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to send signal for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+
+ return SendErrorResponse (0x52);
+ }
+ }
+
+ // Resume the threads.
+ error = m_debugged_process_sp->Resume (resume_actions);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to resume threads for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+
+ return SendErrorResponse (0x38);
+ }
+
+ // Don't send an "OK" packet; response is the stopped/exited message.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_c (StringExtractorGDBRemote &packet, bool skip_file_pos_adjustment)
+{
+ if (!IsGdbServer ())
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__);
+
+ // We reuse this method in vCont - don't double adjust the file position.
+ if (!skip_file_pos_adjustment)
+ packet.SetFilePos (::strlen ("c"));
+
+ // For now just support all continue.
+ const bool has_continue_address = (packet.GetBytesLeft () > 0);
+ if (has_continue_address)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s not implemented for c{address} variant [%s remains]", __FUNCTION__, packet.Peek ());
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+ }
+
+ // Ensure we have a native process.
+ if (!m_debugged_process_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__);
+ return SendErrorResponse (0x36);
+ }
+
+ // Build the ResumeActionList
+ lldb_private::ResumeActionList actions (StateType::eStateRunning, 0);
+
+ Error error = m_debugged_process_sp->Resume (actions);
+ if (error.Fail ())
+ {
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s c failed for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ }
+ return SendErrorResponse (GDBRemoteServerError::eErrorResume);
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // No response required from continue.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vCont_actions (StringExtractorGDBRemote &packet)
+{
+ if (!IsGdbServer ())
+ {
+ // only llgs supports $vCont.
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+ }
+
+ // We handle $vCont messages for c.
+ // TODO add C, s and S.
+ StreamString response;
+ response.Printf("vCont;c;C;s;S");
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vCont (StringExtractorGDBRemote &packet)
+{
+ if (!IsGdbServer ())
+ {
+ // only llgs supports $vCont
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+ }
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s handling vCont packet", __FUNCTION__);
+
+ packet.SetFilePos (::strlen ("vCont"));
+
+ // Check if this is all continue (no options or ";c").
+ if (!packet.GetBytesLeft () || (::strcmp (packet.Peek (), ";c") == 0))
+ {
+ // Move the packet past the ";c".
+ if (packet.GetBytesLeft ())
+ packet.SetFilePos (packet.GetFilePos () + ::strlen (";c"));
+
+ const bool skip_file_pos_adjustment = true;
+ return Handle_c (packet, skip_file_pos_adjustment);
+ }
+ else if (::strcmp (packet.Peek (), ";s") == 0)
+ {
+ // Move past the ';', then do a simple 's'.
+ packet.SetFilePos (packet.GetFilePos () + 1);
+ return Handle_s (packet);
+ }
+
+ // Ensure we have a native process.
+ if (!m_debugged_process_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__);
+ return SendErrorResponse (0x36);
+ }
+
+ ResumeActionList thread_actions;
+
+ while (packet.GetBytesLeft () && *packet.Peek () == ';')
+ {
+ // Skip the semi-colon.
+ packet.GetChar ();
+
+ // Build up the thread action.
+ ResumeAction thread_action;
+ thread_action.tid = LLDB_INVALID_THREAD_ID;
+ thread_action.state = eStateInvalid;
+ thread_action.signal = 0;
+
+ const char action = packet.GetChar ();
+ switch (action)
+ {
+ case 'C':
+ thread_action.signal = packet.GetHexMaxU32 (false, 0);
+ if (thread_action.signal == 0)
+ return SendIllFormedResponse (packet, "Could not parse signal in vCont packet C action");
+ // Fall through to next case...
+
+ case 'c':
+ // Continue
+ thread_action.state = eStateRunning;
+ break;
+
+ case 'S':
+ thread_action.signal = packet.GetHexMaxU32 (false, 0);
+ if (thread_action.signal == 0)
+ return SendIllFormedResponse (packet, "Could not parse signal in vCont packet S action");
+ // Fall through to next case...
+
+ case 's':
+ // Step
+ thread_action.state = eStateStepping;
+ break;
+
+ default:
+ return SendIllFormedResponse (packet, "Unsupported vCont action");
+ break;
+ }
+
+ // Parse out optional :{thread-id} value.
+ if (packet.GetBytesLeft () && (*packet.Peek () == ':'))
+ {
+ // Consume the separator.
+ packet.GetChar ();
+
+ thread_action.tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID);
+ if (thread_action.tid == LLDB_INVALID_THREAD_ID)
+ return SendIllFormedResponse (packet, "Could not parse thread number in vCont packet");
+ }
+
+ thread_actions.Append (thread_action);
+ }
+
+ // If a default action for all other threads wasn't mentioned
+ // then we should stop the threads.
+ thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0);
+
+ Error error = m_debugged_process_sp->Resume (thread_actions);
+ if (error.Fail ())
+ {
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s vCont failed for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ }
+ return SendErrorResponse (GDBRemoteServerError::eErrorResume);
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // No response required from vCont.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet)
{
// Send response first before changing m_send_acks to we ack this packet
@@ -1288,7 +2519,7 @@ GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &
{
std::string path;
packet.GetHexByteString(path);
- Error error = Host::MakeDirectory(path.c_str(),mode);
+ Error error = FileSystem::MakeDirectory(path.c_str(), mode);
if (error.Success())
return SendPacketNoLock ("OK", 2);
else
@@ -1307,7 +2538,7 @@ GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &
{
std::string path;
packet.GetHexByteString(path);
- Error error = Host::SetFilePermissions (path.c_str(), mode);
+ Error error = FileSystem::SetFilePermissions(path.c_str(), mode);
if (error.Success())
return SendPacketNoLock ("OK", 2);
else
@@ -1457,7 +2688,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packe
packet.GetHexByteString(path);
if (!path.empty())
{
- lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false));
+ lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path.c_str(), false));
StreamString response;
response.PutChar('F');
response.PutHex64(retcode);
@@ -1498,7 +2729,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &pac
packet.GetHexByteString(path);
if (!path.empty())
{
- bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false));
+ bool retcode = FileSystem::GetFileExists(FileSpec(path.c_str(), false));
StreamString response;
response.PutChar('F');
response.PutChar(',');
@@ -1519,7 +2750,7 @@ GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &pa
packet.GetHexByteStringTerminatedBy(dst, ',');
packet.GetChar(); // Skip ',' char
packet.GetHexByteString(src);
- Error error = Host::Symlink(src.c_str(), dst.c_str());
+ Error error = FileSystem::Symlink(src.c_str(), dst.c_str());
StreamString response;
response.Printf("F%u,%u", error.GetError(), error.GetError());
return SendPacketNoLock(response.GetData(), response.GetSize());
@@ -1531,7 +2762,7 @@ GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &pac
packet.SetFilePos(::strlen("vFile:unlink:"));
std::string path;
packet.GetHexByteString(path);
- Error error = Host::Unlink(path.c_str());
+ Error error = FileSystem::Unlink(path.c_str());
StreamString response;
response.Printf("F%u,%u", error.GetError(), error.GetError());
return SendPacketNoLock(response.GetData(), response.GetSize());
@@ -1579,6 +2810,94 @@ GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &
return SendErrorResponse(24);
}
+void
+GDBRemoteCommunicationServer::SetCurrentThreadID (lldb::tid_t tid)
+{
+ assert (IsGdbServer () && "SetCurrentThreadID() called when not GdbServer code");
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s setting current thread id to %" PRIu64, __FUNCTION__, tid);
+
+ m_current_tid = tid;
+ if (m_debugged_process_sp)
+ m_debugged_process_sp->SetCurrentThreadID (m_current_tid);
+}
+
+void
+GDBRemoteCommunicationServer::SetContinueThreadID (lldb::tid_t tid)
+{
+ assert (IsGdbServer () && "SetContinueThreadID() called when not GdbServer code");
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s setting continue thread id to %" PRIu64, __FUNCTION__, tid);
+
+ m_continue_tid = tid;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_stop_reason (StringExtractorGDBRemote &packet)
+{
+ // Handle the $? gdbremote command.
+ if (!IsGdbServer ())
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_stop_reason() unimplemented");
+
+ // If no process, indicate error
+ if (!m_debugged_process_sp)
+ return SendErrorResponse (02);
+
+ return SendStopReasonForState (m_debugged_process_sp->GetState (), true);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ switch (process_state)
+ {
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ // NOTE: gdb protocol doc looks like it should return $OK
+ // when everything is running (i.e. no stopped result).
+ return PacketResult::Success; // Ignore
+
+ case eStateSuspended:
+ case eStateStopped:
+ case eStateCrashed:
+ {
+ lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID ();
+ // Make sure we set the current thread so g and p packets return
+ // the data the gdb will expect.
+ SetCurrentThreadID (tid);
+ return SendStopReplyPacketForThread (tid);
+ }
+
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateExited:
+ if (flush_on_exit)
+ FlushInferiorOutput ();
+ return SendWResponse(m_debugged_process_sp.get());
+
+ default:
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", current state reporting not handled: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ StateAsCString (process_state));
+ }
+ break;
+ }
+
+ return SendErrorResponse (0);
+}
+
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet)
{
@@ -1595,7 +2914,7 @@ GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet
{
uint64_t a,b;
StreamGDBRemote response;
- if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false)
+ if (FileSystem::CalculateMD5(FileSpec(path.c_str(), false), a, b) == false)
{
response.PutCString("F,");
response.PutCString("x");
@@ -1611,3 +2930,1385 @@ GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet
return SendErrorResponse(25);
}
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qRegisterInfo (StringExtractorGDBRemote &packet)
+{
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qRegisterInfo() unimplemented");
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse (68);
+
+ // Ensure we have a thread.
+ NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadAtIndex (0));
+ if (!thread_sp)
+ return SendErrorResponse (69);
+
+ // Get the register context for the first thread.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ return SendErrorResponse (69);
+
+ // Parse out the register number from the request.
+ packet.SetFilePos (strlen("qRegisterInfo"));
+ const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (reg_index == std::numeric_limits<uint32_t>::max ())
+ return SendErrorResponse (69);
+
+ // Return the end of registers response if we've iterated one past the end of the register set.
+ if (reg_index >= reg_context_sp->GetRegisterCount ())
+ return SendErrorResponse (69);
+
+ const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ return SendErrorResponse (69);
+
+ // Build the reginfos response.
+ StreamGDBRemote response;
+
+ response.PutCString ("name:");
+ response.PutCString (reg_info->name);
+ response.PutChar (';');
+
+ if (reg_info->alt_name && reg_info->alt_name[0])
+ {
+ response.PutCString ("alt-name:");
+ response.PutCString (reg_info->alt_name);
+ response.PutChar (';');
+ }
+
+ response.Printf ("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", reg_info->byte_size * 8, reg_info->byte_offset);
+
+ switch (reg_info->encoding)
+ {
+ case eEncodingUint: response.PutCString ("encoding:uint;"); break;
+ case eEncodingSint: response.PutCString ("encoding:sint;"); break;
+ case eEncodingIEEE754: response.PutCString ("encoding:ieee754;"); break;
+ case eEncodingVector: response.PutCString ("encoding:vector;"); break;
+ default: break;
+ }
+
+ switch (reg_info->format)
+ {
+ case eFormatBinary: response.PutCString ("format:binary;"); break;
+ case eFormatDecimal: response.PutCString ("format:decimal;"); break;
+ case eFormatHex: response.PutCString ("format:hex;"); break;
+ case eFormatFloat: response.PutCString ("format:float;"); break;
+ case eFormatVectorOfSInt8: response.PutCString ("format:vector-sint8;"); break;
+ case eFormatVectorOfUInt8: response.PutCString ("format:vector-uint8;"); break;
+ case eFormatVectorOfSInt16: response.PutCString ("format:vector-sint16;"); break;
+ case eFormatVectorOfUInt16: response.PutCString ("format:vector-uint16;"); break;
+ case eFormatVectorOfSInt32: response.PutCString ("format:vector-sint32;"); break;
+ case eFormatVectorOfUInt32: response.PutCString ("format:vector-uint32;"); break;
+ case eFormatVectorOfFloat32: response.PutCString ("format:vector-float32;"); break;
+ case eFormatVectorOfUInt128: response.PutCString ("format:vector-uint128;"); break;
+ default: break;
+ };
+
+ const char *const register_set_name = reg_context_sp->GetRegisterSetNameForRegisterAtIndex(reg_index);
+ if (register_set_name)
+ {
+ response.PutCString ("set:");
+ response.PutCString (register_set_name);
+ response.PutChar (';');
+ }
+
+ if (reg_info->kinds[RegisterKind::eRegisterKindGCC] != LLDB_INVALID_REGNUM)
+ response.Printf ("gcc:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindGCC]);
+
+ if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM)
+ response.Printf ("dwarf:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindDWARF]);
+
+ switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric])
+ {
+ case LLDB_REGNUM_GENERIC_PC: response.PutCString("generic:pc;"); break;
+ case LLDB_REGNUM_GENERIC_SP: response.PutCString("generic:sp;"); break;
+ case LLDB_REGNUM_GENERIC_FP: response.PutCString("generic:fp;"); break;
+ case LLDB_REGNUM_GENERIC_RA: response.PutCString("generic:ra;"); break;
+ case LLDB_REGNUM_GENERIC_FLAGS: response.PutCString("generic:flags;"); break;
+ case LLDB_REGNUM_GENERIC_ARG1: response.PutCString("generic:arg1;"); break;
+ case LLDB_REGNUM_GENERIC_ARG2: response.PutCString("generic:arg2;"); break;
+ case LLDB_REGNUM_GENERIC_ARG3: response.PutCString("generic:arg3;"); break;
+ case LLDB_REGNUM_GENERIC_ARG4: response.PutCString("generic:arg4;"); break;
+ case LLDB_REGNUM_GENERIC_ARG5: response.PutCString("generic:arg5;"); break;
+ case LLDB_REGNUM_GENERIC_ARG6: response.PutCString("generic:arg6;"); break;
+ case LLDB_REGNUM_GENERIC_ARG7: response.PutCString("generic:arg7;"); break;
+ case LLDB_REGNUM_GENERIC_ARG8: response.PutCString("generic:arg8;"); break;
+ default: break;
+ }
+
+ if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
+ {
+ response.PutCString ("container-regs:");
+ int i = 0;
+ for (const uint32_t *reg_num = reg_info->value_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i)
+ {
+ if (i > 0)
+ response.PutChar (',');
+ response.Printf ("%" PRIx32, *reg_num);
+ }
+ response.PutChar (';');
+ }
+
+ if (reg_info->invalidate_regs && reg_info->invalidate_regs[0])
+ {
+ response.PutCString ("invalidate-regs:");
+ int i = 0;
+ for (const uint32_t *reg_num = reg_info->invalidate_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i)
+ {
+ if (i > 0)
+ response.PutChar (',');
+ response.Printf ("%" PRIx32, *reg_num);
+ }
+ response.PutChar (';');
+ }
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qfThreadInfo (StringExtractorGDBRemote &packet)
+{
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qfThreadInfo() unimplemented");
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s() no process (%s), returning OK", __FUNCTION__, m_debugged_process_sp ? "invalid process id" : "null m_debugged_process_sp");
+ return SendOKResponse ();
+ }
+
+ StreamGDBRemote response;
+ response.PutChar ('m');
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s() starting thread iteration", __FUNCTION__);
+
+ NativeThreadProtocolSP thread_sp;
+ uint32_t thread_index;
+ for (thread_index = 0, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index);
+ thread_sp;
+ ++thread_index, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s() iterated thread %" PRIu32 "(%s, tid=0x%" PRIx64 ")", __FUNCTION__, thread_index, thread_sp ? "is not null" : "null", thread_sp ? thread_sp->GetID () : LLDB_INVALID_THREAD_ID);
+ if (thread_index > 0)
+ response.PutChar(',');
+ response.Printf ("%" PRIx64, thread_sp->GetID ());
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s() finished thread iteration", __FUNCTION__);
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qsThreadInfo (StringExtractorGDBRemote &packet)
+{
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_qsThreadInfo() unimplemented");
+
+ // FIXME for now we return the full thread list in the initial packet and always do nothing here.
+ return SendPacketNoLock ("l", 1);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_p (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_p() unimplemented");
+
+ // Parse out the register number from the request.
+ packet.SetFilePos (strlen("p"));
+ const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (reg_index == std::numeric_limits<uint32_t>::max ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return SendErrorResponse (0x15);
+ }
+
+ // Get the thread to use.
+ NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+ if (!thread_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no thread available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Get the thread's register context.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+ return SendErrorResponse (0x15);
+ }
+
+ // Return the end of registers response if we've iterated one past the end of the register set.
+ if (reg_index >= reg_context_sp->GetRegisterCount ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetRegisterCount ());
+ return SendErrorResponse (0x15);
+ }
+
+ const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index);
+ return SendErrorResponse (0x15);
+ }
+
+ // Build the reginfos response.
+ StreamGDBRemote response;
+
+ // Retrieve the value
+ RegisterValue reg_value;
+ Error error = reg_context_sp->ReadRegister (reg_info, reg_value);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, read of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ());
+ return SendErrorResponse (0x15);
+ }
+
+ const uint8_t *const data = reinterpret_cast<const uint8_t*> (reg_value.GetBytes ());
+ if (!data)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to get data bytes from requested register %" PRIu32, __FUNCTION__, reg_index);
+ return SendErrorResponse (0x15);
+ }
+
+ // FIXME flip as needed to get data in big/little endian format for this host.
+ for (uint32_t i = 0; i < reg_value.GetByteSize (); ++i)
+ response.PutHex8 (data[i]);
+
+ return SendPacketNoLock (response.GetData (), response.GetSize ());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_P (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_P() unimplemented");
+
+ // Ensure there is more content.
+ if (packet.GetBytesLeft () < 1)
+ return SendIllFormedResponse (packet, "Empty P packet");
+
+ // Parse out the register number from the request.
+ packet.SetFilePos (strlen("P"));
+ const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (reg_index == std::numeric_limits<uint32_t>::max ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return SendErrorResponse (0x29);
+ }
+
+ // Note debugserver would send an E30 here.
+ if ((packet.GetBytesLeft () < 1) || (packet.GetChar () != '='))
+ return SendIllFormedResponse (packet, "P packet missing '=' char after register number");
+
+ // Get process architecture.
+ ArchSpec process_arch;
+ if (!m_debugged_process_sp || !m_debugged_process_sp->GetArchitecture (process_arch))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to retrieve inferior architecture", __FUNCTION__);
+ return SendErrorResponse (0x49);
+ }
+
+ // Parse out the value.
+ const uint64_t raw_value = packet.GetHexMaxU64 (process_arch.GetByteOrder () == lldb::eByteOrderLittle, std::numeric_limits<uint64_t>::max ());
+
+ // Get the thread to use.
+ NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+ if (!thread_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no thread available (thread index 0)", __FUNCTION__);
+ return SendErrorResponse (0x28);
+ }
+
+ // Get the thread's register context.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+ return SendErrorResponse (0x15);
+ }
+
+ const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index);
+ return SendErrorResponse (0x48);
+ }
+
+ // Return the end of registers response if we've iterated one past the end of the register set.
+ if (reg_index >= reg_context_sp->GetRegisterCount ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetRegisterCount ());
+ return SendErrorResponse (0x47);
+ }
+
+
+ // Build the reginfos response.
+ StreamGDBRemote response;
+
+ // FIXME Could be suffixed with a thread: parameter.
+ // That thread then needs to be fed back into the reg context retrieval above.
+ Error error = reg_context_sp->WriteRegisterFromUnsigned (reg_info, raw_value);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, write of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ());
+ return SendErrorResponse (0x32);
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_H (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_H() unimplemented");
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out which variant of $H is requested.
+ packet.SetFilePos (strlen("H"));
+ if (packet.GetBytesLeft () < 1)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, H command missing {g,c} variant", __FUNCTION__);
+ return SendIllFormedResponse (packet, "H command missing {g,c} variant");
+ }
+
+ const char h_variant = packet.GetChar ();
+ switch (h_variant)
+ {
+ case 'g':
+ break;
+
+ case 'c':
+ break;
+
+ default:
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, invalid $H variant %c", __FUNCTION__, h_variant);
+ return SendIllFormedResponse (packet, "H variant unsupported, should be c or g");
+ }
+
+ // Parse out the thread number.
+ // FIXME return a parse success/fail value. All values are valid here.
+ const lldb::tid_t tid = packet.GetHexMaxU64 (false, std::numeric_limits<lldb::tid_t>::max ());
+
+ // Ensure we have the given thread when not specifying -1 (all threads) or 0 (any thread).
+ if (tid != LLDB_INVALID_THREAD_ID && tid != 0)
+ {
+ NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid));
+ if (!thread_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, tid %" PRIu64 " not found", __FUNCTION__, tid);
+ return SendErrorResponse (0x15);
+ }
+ }
+
+ // Now switch the given thread type.
+ switch (h_variant)
+ {
+ case 'g':
+ SetCurrentThreadID (tid);
+ break;
+
+ case 'c':
+ SetContinueThreadID (tid);
+ break;
+
+ default:
+ assert (false && "unsupported $H variant - shouldn't get here");
+ return SendIllFormedResponse (packet, "H variant unsupported, should be c or g");
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_interrupt (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ {
+ // Only supported on llgs
+ return SendUnimplementedResponse ("");
+ }
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Build the ResumeActionList - stop everything.
+ lldb_private::ResumeActionList actions (StateType::eStateStopped, 0);
+
+ Error error = m_debugged_process_sp->Resume (actions);
+ if (error.Fail ())
+ {
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServer::%s failed for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ }
+ return SendErrorResponse (GDBRemoteServerError::eErrorResume);
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s stopped process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // No response required from stop all.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_m (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ {
+ // Only supported on llgs
+ return SendUnimplementedResponse ("");
+ }
+
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos (strlen("m"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short m packet");
+
+ // Read the address. Punting on validation.
+ // FIXME replace with Hex U64 read with no default value that fails on failed read.
+ const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0);
+
+ // Validate comma.
+ if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ','))
+ return SendIllFormedResponse(packet, "Comma sep missing in m packet");
+
+ // Get # bytes to read.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Length missing in m packet");
+
+ const uint64_t byte_count = packet.GetHexMaxU64(false, 0);
+ if (byte_count == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s nothing to read: zero-length packet", __FUNCTION__);
+ return PacketResult::Success;
+ }
+
+ // Allocate the response buffer.
+ std::string buf(byte_count, '\0');
+ if (buf.empty())
+ return SendErrorResponse (0x78);
+
+
+ // Retrieve the process memory.
+ lldb::addr_t bytes_read = 0;
+ lldb_private::Error error = m_debugged_process_sp->ReadMemory (read_addr, &buf[0], byte_count, bytes_read);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to read. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, error.AsCString ());
+ return SendErrorResponse (0x08);
+ }
+
+ if (bytes_read == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read %" PRIu64 " of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, bytes_read, byte_count);
+ return SendErrorResponse (0x08);
+ }
+
+ StreamGDBRemote response;
+ for (lldb::addr_t i = 0; i < bytes_read; ++i)
+ response.PutHex8(buf[i]);
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetDetachOnError:"));
+ if (packet.GetU32(0))
+ m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError);
+ else
+ m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError);
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_M (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Ensure we're llgs.
+ if (!IsGdbServer())
+ {
+ // Only supported on llgs
+ return SendUnimplementedResponse ("");
+ }
+
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos (strlen("M"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short M packet");
+
+ // Read the address. Punting on validation.
+ // FIXME replace with Hex U64 read with no default value that fails on failed read.
+ const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0);
+
+ // Validate comma.
+ if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ','))
+ return SendIllFormedResponse(packet, "Comma sep missing in M packet");
+
+ // Get # bytes to read.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Length missing in M packet");
+
+ const uint64_t byte_count = packet.GetHexMaxU64(false, 0);
+ if (byte_count == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s nothing to write: zero-length packet", __FUNCTION__);
+ return PacketResult::Success;
+ }
+
+ // Validate colon.
+ if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':'))
+ return SendIllFormedResponse(packet, "Comma sep missing in M packet after byte length");
+
+ // Allocate the conversion buffer.
+ std::vector<uint8_t> buf(byte_count, 0);
+ if (buf.empty())
+ return SendErrorResponse (0x78);
+
+ // Convert the hex memory write contents to bytes.
+ StreamGDBRemote response;
+ const uint64_t convert_count = static_cast<uint64_t> (packet.GetHexBytes (&buf[0], byte_count, 0));
+ if (convert_count != byte_count)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": asked to write %" PRIu64 " bytes, but only found %" PRIu64 " to convert.", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count, convert_count);
+ return SendIllFormedResponse (packet, "M content byte length specified did not match hex-encoded content length");
+ }
+
+ // Write the process memory.
+ lldb::addr_t bytes_written = 0;
+ lldb_private::Error error = m_debugged_process_sp->WriteMemory (write_addr, &buf[0], byte_count, bytes_written);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to write. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+
+ if (bytes_written == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": wrote %" PRIu64 " of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, bytes_written, byte_count);
+ return SendErrorResponse (0x09);
+ }
+
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("");
+
+ // Currently only the NativeProcessProtocol knows if it can handle a qMemoryRegionInfoSupported
+ // request, but we're not guaranteed to be attached to a process. For now we'll assume the
+ // client only asks this when a process is being debugged.
+
+ // Ensure we have a process running; otherwise, we can't figure this out
+ // since we won't have a NativeProcessProtocol.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Test if we can get any region back when asking for the region around NULL.
+ MemoryRegionInfo region_info;
+ const Error error = m_debugged_process_sp->GetMemoryRegionInfo (0, region_info);
+ if (error.Fail ())
+ {
+ // We don't support memory region info collection for this NativeProcessProtocol.
+ return SendUnimplementedResponse ("");
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("");
+
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos (strlen("qMemoryRegionInfo:"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet");
+
+ // Read the address. Punting on validation.
+ const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0);
+
+ StreamGDBRemote response;
+
+ // Get the memory region info for the target address.
+ MemoryRegionInfo region_info;
+ const Error error = m_debugged_process_sp->GetMemoryRegionInfo (read_addr, region_info);
+ if (error.Fail ())
+ {
+ // Return the error message.
+
+ response.PutCString ("error:");
+ response.PutCStringAsRawHex8 (error.AsCString ());
+ response.PutChar (';');
+ }
+ else
+ {
+ // Range start and size.
+ response.Printf ("start:%" PRIx64 ";size:%" PRIx64 ";", region_info.GetRange ().GetRangeBase (), region_info.GetRange ().GetByteSize ());
+
+ // Permissions.
+ if (region_info.GetReadable () ||
+ region_info.GetWritable () ||
+ region_info.GetExecutable ())
+ {
+ // Write permissions info.
+ response.PutCString ("permissions:");
+
+ if (region_info.GetReadable ())
+ response.PutChar ('r');
+ if (region_info.GetWritable ())
+ response.PutChar('w');
+ if (region_info.GetExecutable())
+ response.PutChar ('x');
+
+ response.PutChar (';');
+ }
+ }
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_Z (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("");
+
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out software or hardware breakpoint requested.
+ packet.SetFilePos (strlen("Z"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short Z packet, missing software/hardware specifier");
+
+ bool want_breakpoint = true;
+ bool want_hardware = false;
+
+ const char breakpoint_type_char = packet.GetChar ();
+ switch (breakpoint_type_char)
+ {
+ case '0': want_hardware = false; want_breakpoint = true; break;
+ case '1': want_hardware = true; want_breakpoint = true; break;
+ case '2': want_breakpoint = false; break;
+ case '3': want_breakpoint = false; break;
+ default:
+ return SendIllFormedResponse(packet, "Z packet had invalid software/hardware specifier");
+
+ }
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after breakpoint type");
+
+ // FIXME implement watchpoint support.
+ if (!want_breakpoint)
+ return SendUnimplementedResponse ("watchpoint support not yet implemented");
+
+ // Parse out the breakpoint address.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short Z packet, missing address");
+ const lldb::addr_t breakpoint_addr = packet.GetHexMaxU64(false, 0);
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after address");
+
+ // Parse out the breakpoint kind (i.e. size hint for opcode size).
+ const uint32_t kind = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (kind == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse kind argument");
+
+ if (want_breakpoint)
+ {
+ // Try to set the breakpoint.
+ const Error error = m_debugged_process_sp->SetBreakpoint (breakpoint_addr, kind, want_hardware);
+ if (error.Success ())
+ return SendOKResponse ();
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to set breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+ }
+
+ // FIXME fix up after watchpoints are handled.
+ return SendUnimplementedResponse ("");
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_z (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("");
+
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out software or hardware breakpoint requested.
+ packet.SetFilePos (strlen("Z"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short z packet, missing software/hardware specifier");
+
+ bool want_breakpoint = true;
+
+ const char breakpoint_type_char = packet.GetChar ();
+ switch (breakpoint_type_char)
+ {
+ case '0': want_breakpoint = true; break;
+ case '1': want_breakpoint = true; break;
+ case '2': want_breakpoint = false; break;
+ case '3': want_breakpoint = false; break;
+ default:
+ return SendIllFormedResponse(packet, "z packet had invalid software/hardware specifier");
+
+ }
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after breakpoint type");
+
+ // FIXME implement watchpoint support.
+ if (!want_breakpoint)
+ return SendUnimplementedResponse ("watchpoint support not yet implemented");
+
+ // Parse out the breakpoint address.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short z packet, missing address");
+ const lldb::addr_t breakpoint_addr = packet.GetHexMaxU64(false, 0);
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after address");
+
+ // Parse out the breakpoint kind (i.e. size hint for opcode size).
+ const uint32_t kind = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (kind == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse(packet, "Malformed z packet, failed to parse kind argument");
+
+ if (want_breakpoint)
+ {
+ // Try to set the breakpoint.
+ const Error error = m_debugged_process_sp->RemoveBreakpoint (breakpoint_addr);
+ if (error.Success ())
+ return SendOKResponse ();
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to remove breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+ }
+
+ // FIXME fix up after watchpoints are handled.
+ return SendUnimplementedResponse ("");
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_s (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("");
+
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x32);
+ }
+
+ // We first try to use a continue thread id. If any one or any all set, use the current thread.
+ // Bail out if we don't have a thread id.
+ lldb::tid_t tid = GetContinueThreadID ();
+ if (tid == 0 || tid == LLDB_INVALID_THREAD_ID)
+ tid = GetCurrentThreadID ();
+ if (tid == LLDB_INVALID_THREAD_ID)
+ return SendErrorResponse (0x33);
+
+ // Double check that we have such a thread.
+ // TODO investigate: on MacOSX we might need to do an UpdateThreads () here.
+ NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID (tid);
+ if (!thread_sp || thread_sp->GetID () != tid)
+ return SendErrorResponse (0x33);
+
+ // Create the step action for the given thread.
+ lldb_private::ResumeAction action = { tid, eStateStepping, 0 };
+
+ // Setup the actions list.
+ lldb_private::ResumeActionList actions;
+ actions.Append (action);
+
+ // All other threads stop while we're single stepping a thread.
+ actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
+ Error error = m_debugged_process_sp->Resume (actions);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " Resume() failed with error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), tid, error.AsCString ());
+ return SendErrorResponse(0x49);
+ }
+
+ // No response here - the stop or exit will come from the resulting action.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_qSupported (StringExtractorGDBRemote &packet)
+{
+ StreamGDBRemote response;
+
+ // Features common to lldb-platform and llgs.
+ uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less
+ response.Printf ("PacketSize=%x", max_packet_size);
+
+ response.PutCString (";QStartNoAckMode+");
+ response.PutCString (";QThreadSuffixSupported+");
+ response.PutCString (";QListThreadsInStopReply+");
+#if defined(__linux__)
+ response.PutCString (";qXfer:auxv:read+");
+#endif
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet)
+{
+ m_thread_suffix_supported = true;
+ return SendOKResponse();
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet)
+{
+ m_list_threads_in_stop_reply = true;
+ return SendOKResponse();
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet)
+{
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("only supported for lldb-gdbserver");
+
+ // *BSD impls should be able to do this too.
+#if defined(__linux__)
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Parse out the offset.
+ packet.SetFilePos (strlen("qXfer:auxv:read::"));
+ if (packet.GetBytesLeft () < 1)
+ return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset");
+
+ const uint64_t auxv_offset = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ());
+ if (auxv_offset == std::numeric_limits<uint64_t>::max ())
+ return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset");
+
+ // Parse out comma.
+ if (packet.GetBytesLeft () < 1 || packet.GetChar () != ',')
+ return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing comma after offset");
+
+ // Parse out the length.
+ const uint64_t auxv_length = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ());
+ if (auxv_length == std::numeric_limits<uint64_t>::max ())
+ return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing length");
+
+ // Grab the auxv data if we need it.
+ if (!m_active_auxv_buffer_sp)
+ {
+ // Make sure we have a valid process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x10);
+ }
+
+ // Grab the auxv data.
+ m_active_auxv_buffer_sp = Host::GetAuxvData (m_debugged_process_sp->GetID ());
+ if (!m_active_auxv_buffer_sp || m_active_auxv_buffer_sp->GetByteSize () == 0)
+ {
+ // Hmm, no auxv data, call that an error.
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed, no auxv data retrieved", __FUNCTION__);
+ m_active_auxv_buffer_sp.reset ();
+ return SendErrorResponse (0x11);
+ }
+ }
+
+ // FIXME find out if/how I lock the stream here.
+
+ StreamGDBRemote response;
+ bool done_with_buffer = false;
+
+ if (auxv_offset >= m_active_auxv_buffer_sp->GetByteSize ())
+ {
+ // We have nothing left to send. Mark the buffer as complete.
+ response.PutChar ('l');
+ done_with_buffer = true;
+ }
+ else
+ {
+ // Figure out how many bytes are available starting at the given offset.
+ const uint64_t bytes_remaining = m_active_auxv_buffer_sp->GetByteSize () - auxv_offset;
+
+ // Figure out how many bytes we're going to read.
+ const uint64_t bytes_to_read = (auxv_length > bytes_remaining) ? bytes_remaining : auxv_length;
+
+ // Mark the response type according to whether we're reading the remainder of the auxv data.
+ if (bytes_to_read >= bytes_remaining)
+ {
+ // There will be nothing left to read after this
+ response.PutChar ('l');
+ done_with_buffer = true;
+ }
+ else
+ {
+ // There will still be bytes to read after this request.
+ response.PutChar ('m');
+ }
+
+ // Now write the data in encoded binary form.
+ response.PutEscapedBytes (m_active_auxv_buffer_sp->GetBytes () + auxv_offset, bytes_to_read);
+ }
+
+ if (done_with_buffer)
+ m_active_auxv_buffer_sp.reset ();
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+#else
+ return SendUnimplementedResponse ("not implemented on this platform");
+#endif
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_QSaveRegisterState (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("only supported for lldb-gdbserver");
+
+ // Move past packet name.
+ packet.SetFilePos (strlen ("QSaveRegisterState"));
+
+ // Get the thread to use.
+ NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+ if (!thread_sp)
+ {
+ if (m_thread_suffix_supported)
+ return SendIllFormedResponse (packet, "No thread specified in QSaveRegisterState packet");
+ else
+ return SendIllFormedResponse (packet, "No thread was is set with the Hg packet");
+ }
+
+ // Grab the register context for the thread.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+ return SendErrorResponse (0x15);
+ }
+
+ // Save registers to a buffer.
+ DataBufferSP register_data_sp;
+ Error error = reg_context_sp->ReadAllRegisterValues (register_data_sp);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to save all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+ return SendErrorResponse (0x75);
+ }
+
+ // Allocate a new save id.
+ const uint32_t save_id = GetNextSavedRegistersID ();
+ assert ((m_saved_registers_map.find (save_id) == m_saved_registers_map.end ()) && "GetNextRegisterSaveID() returned an existing register save id");
+
+ // Save the register data buffer under the save id.
+ {
+ Mutex::Locker locker (m_saved_registers_mutex);
+ m_saved_registers_map[save_id] = register_data_sp;
+ }
+
+ // Write the response.
+ StreamGDBRemote response;
+ response.Printf ("%" PRIu32, save_id);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("only supported for lldb-gdbserver");
+
+ // Parse out save id.
+ packet.SetFilePos (strlen ("QRestoreRegisterState:"));
+ if (packet.GetBytesLeft () < 1)
+ return SendIllFormedResponse (packet, "QRestoreRegisterState packet missing register save id");
+
+ const uint32_t save_id = packet.GetU32 (0);
+ if (save_id == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s QRestoreRegisterState packet has malformed save id, expecting decimal uint32_t", __FUNCTION__);
+ return SendErrorResponse (0x76);
+ }
+
+ // Get the thread to use.
+ NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+ if (!thread_sp)
+ {
+ if (m_thread_suffix_supported)
+ return SendIllFormedResponse (packet, "No thread specified in QRestoreRegisterState packet");
+ else
+ return SendIllFormedResponse (packet, "No thread was is set with the Hg packet");
+ }
+
+ // Grab the register context for the thread.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+ return SendErrorResponse (0x15);
+ }
+
+ // Retrieve register state buffer, then remove from the list.
+ DataBufferSP register_data_sp;
+ {
+ Mutex::Locker locker (m_saved_registers_mutex);
+
+ // Find the register set buffer for the given save id.
+ auto it = m_saved_registers_map.find (save_id);
+ if (it == m_saved_registers_map.end ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " does not have a register set save buffer for id %" PRIu32, __FUNCTION__, m_debugged_process_sp->GetID (), save_id);
+ return SendErrorResponse (0x77);
+ }
+ register_data_sp = it->second;
+
+ // Remove it from the map.
+ m_saved_registers_map.erase (it);
+ }
+
+ Error error = reg_context_sp->WriteAllRegisterValues (register_data_sp);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to restore all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+ return SendErrorResponse (0x77);
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_vAttach (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // We don't support if we're not llgs.
+ if (!IsGdbServer())
+ return SendUnimplementedResponse ("only supported for lldb-gdbserver");
+
+ // Consume the ';' after vAttach.
+ packet.SetFilePos (strlen ("vAttach"));
+ if (!packet.GetBytesLeft () || packet.GetChar () != ';')
+ return SendIllFormedResponse (packet, "vAttach missing expected ';'");
+
+ // Grab the PID to which we will attach (assume hex encoding).
+ lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16);
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendIllFormedResponse (packet, "vAttach failed to parse the process id");
+
+ // Attempt to attach.
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s attempting to attach to pid %" PRIu64, __FUNCTION__, pid);
+
+ Error error = AttachToProcess (pid);
+
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s failed to attach to pid %" PRIu64 ": %s\n", __FUNCTION__, pid, error.AsCString());
+ return SendErrorResponse (0x01);
+ }
+
+ // Notify we attached by sending a stop packet.
+ return SendStopReasonForState (m_debugged_process_sp->GetState (), true);
+
+ return PacketResult::Success;
+}
+
+void
+GDBRemoteCommunicationServer::FlushInferiorOutput ()
+{
+ // If we're not monitoring an inferior's terminal, ignore this.
+ if (!m_stdio_communication.IsConnected())
+ return;
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s() called", __FUNCTION__);
+
+ // FIXME implement a timeout on the join.
+ m_stdio_communication.JoinReadThread();
+}
+
+void
+GDBRemoteCommunicationServer::MaybeCloseInferiorTerminalConnection ()
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Tell the stdio connection to shut down.
+ if (m_stdio_communication.IsConnected())
+ {
+ auto connection = m_stdio_communication.GetConnection();
+ if (connection)
+ {
+ Error error;
+ connection->Disconnect (&error);
+
+ if (error.Success ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s disconnect process terminal stdio - SUCCESS", __FUNCTION__);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s disconnect process terminal stdio - FAIL: %s", __FUNCTION__, error.AsCString ());
+ }
+ }
+ }
+}
+
+
+lldb_private::NativeThreadProtocolSP
+GDBRemoteCommunicationServer::GetThreadFromSuffix (StringExtractorGDBRemote &packet)
+{
+ NativeThreadProtocolSP thread_sp;
+
+ // We have no thread if we don't have a process.
+ if (!m_debugged_process_sp || m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)
+ return thread_sp;
+
+ // If the client hasn't asked for thread suffix support, there will not be a thread suffix.
+ // Use the current thread in that case.
+ if (!m_thread_suffix_supported)
+ {
+ const lldb::tid_t current_tid = GetCurrentThreadID ();
+ if (current_tid == LLDB_INVALID_THREAD_ID)
+ return thread_sp;
+ else if (current_tid == 0)
+ {
+ // Pick a thread.
+ return m_debugged_process_sp->GetThreadAtIndex (0);
+ }
+ else
+ return m_debugged_process_sp->GetThreadByID (current_tid);
+ }
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Parse out the ';'.
+ if (packet.GetBytesLeft () < 1 || packet.GetChar () != ';')
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s gdb-remote parse error: expected ';' prior to start of thread suffix: packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return thread_sp;
+ }
+
+ if (!packet.GetBytesLeft ())
+ return thread_sp;
+
+ // Parse out thread: portion.
+ if (strncmp (packet.Peek (), "thread:", strlen("thread:")) != 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s gdb-remote parse error: expected 'thread:' but not found, packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return thread_sp;
+ }
+ packet.SetFilePos (packet.GetFilePos () + strlen("thread:"));
+ const lldb::tid_t tid = packet.GetHexMaxU64(false, 0);
+ if (tid != 0)
+ return m_debugged_process_sp->GetThreadByID (tid);
+
+ return thread_sp;
+}
+
+lldb::tid_t
+GDBRemoteCommunicationServer::GetCurrentThreadID () const
+{
+ if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID)
+ {
+ // Use whatever the debug process says is the current thread id
+ // since the protocol either didn't specify or specified we want
+ // any/all threads marked as the current thread.
+ if (!m_debugged_process_sp)
+ return LLDB_INVALID_THREAD_ID;
+ return m_debugged_process_sp->GetCurrentThreadID ();
+ }
+ // Use the specific current thread id set by the gdb remote protocol.
+ return m_current_tid;
+}
+
+uint32_t
+GDBRemoteCommunicationServer::GetNextSavedRegistersID ()
+{
+ Mutex::Locker locker (m_saved_registers_mutex);
+ return m_next_saved_registers_id++;
+}
+
+void
+GDBRemoteCommunicationServer::ClearProcessSpecificData ()
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s()", __FUNCTION__);
+
+ // Clear any auxv cached data.
+ // *BSD impls should be able to do this too.
+#if defined(__linux__)
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s clearing auxv buffer (previously %s)",
+ __FUNCTION__,
+ m_active_auxv_buffer_sp ? "was set" : "was not set");
+ m_active_auxv_buffer_sp.reset ();
+#endif
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
index 913c6b673cfb..13c037c0287b 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -14,16 +14,23 @@
// C++ Includes
#include <vector>
#include <set>
+#include <unordered_map>
// Other libraries and framework includes
// Project includes
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Core/Communication.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Target/Process.h"
#include "GDBRemoteCommunication.h"
+#include "../../../Host/common/NativeProcessProtocol.h"
+
class ProcessGDBRemote;
class StringExtractorGDBRemote;
-class GDBRemoteCommunicationServer : public GDBRemoteCommunication
+class GDBRemoteCommunicationServer :
+ public GDBRemoteCommunication,
+ public lldb_private::NativeProcessProtocol::NativeDelegate
{
public:
typedef std::map<uint16_t, lldb::pid_t> PortMap;
@@ -38,12 +45,13 @@ public:
GDBRemoteCommunicationServer(bool is_platform);
GDBRemoteCommunicationServer(bool is_platform,
- const lldb::PlatformSP& platform_sp);
+ const lldb::PlatformSP& platform_sp,
+ lldb::DebuggerSP& debugger_sp);
virtual
~GDBRemoteCommunicationServer();
- bool
+ PacketResult
GetPacketAndSendResponse (uint32_t timeout_usec,
lldb_private::Error &error,
bool &interrupt,
@@ -188,6 +196,31 @@ public:
lldb_private::Error
LaunchProcess ();
+ //------------------------------------------------------------------
+ /// Attach to a process.
+ ///
+ /// This method supports attaching llgs to a process accessible via the
+ /// configured Platform.
+ ///
+ /// @return
+ /// An Error object indicating the success or failure of the
+ /// attach operation.
+ //------------------------------------------------------------------
+ lldb_private::Error
+ AttachToProcess (lldb::pid_t pid);
+
+ //------------------------------------------------------------------
+ // NativeProcessProtocol::NativeDelegate overrides
+ //------------------------------------------------------------------
+ void
+ InitializeDelegate (lldb_private::NativeProcessProtocol *process) override;
+
+ void
+ ProcessStateChanged (lldb_private::NativeProcessProtocol *process, lldb::StateType state) override;
+
+ void
+ DidExec (lldb_private::NativeProcessProtocol *process) override;
+
protected:
lldb::PlatformSP m_platform_sp;
lldb::thread_t m_async_thread;
@@ -199,7 +232,20 @@ protected:
uint32_t m_proc_infos_index;
PortMap m_port_map;
uint16_t m_port_offset;
-
+ lldb::tid_t m_current_tid;
+ lldb::tid_t m_continue_tid;
+ lldb_private::Mutex m_debugged_process_mutex;
+ lldb_private::NativeProcessProtocolSP m_debugged_process_sp;
+ lldb::DebuggerSP m_debugger_sp;
+ Communication m_stdio_communication;
+ bool m_exit_now; // use in asynchronous handling to indicate process should exit.
+ lldb::StateType m_inferior_prev_state;
+ bool m_thread_suffix_supported;
+ bool m_list_threads_in_stop_reply;
+ lldb::DataBufferSP m_active_auxv_buffer_sp;
+ lldb_private::Mutex m_saved_registers_mutex;
+ std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map;
+ uint32_t m_next_saved_registers_id;
PacketResult
SendUnimplementedResponse (const char *packet);
@@ -208,9 +254,24 @@ protected:
SendErrorResponse (uint8_t error);
PacketResult
+ SendIllFormedResponse (const StringExtractorGDBRemote &packet, const char *error_message);
+
+ PacketResult
SendOKResponse ();
PacketResult
+ SendONotification (const char *buffer, uint32_t len);
+
+ PacketResult
+ SendWResponse (lldb_private::NativeProcessProtocol *process);
+
+ PacketResult
+ SendStopReplyPacketForThread (lldb::tid_t tid);
+
+ PacketResult
+ SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit);
+
+ PacketResult
Handle_A (StringExtractorGDBRemote &packet);
PacketResult
@@ -233,7 +294,10 @@ protected:
PacketResult
Handle_qPlatform_chmod (StringExtractorGDBRemote &packet);
-
+
+ PacketResult
+ Handle_qProcessInfo (StringExtractorGDBRemote &packet);
+
PacketResult
Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
@@ -265,6 +329,9 @@ protected:
Handle_QSetDisableASLR (StringExtractorGDBRemote &packet);
PacketResult
+ Handle_QSetDetachOnError (StringExtractorGDBRemote &packet);
+
+ PacketResult
Handle_QSetWorkingDir (StringExtractorGDBRemote &packet);
PacketResult
@@ -281,7 +348,22 @@ protected:
PacketResult
Handle_QSetSTDERR (StringExtractorGDBRemote &packet);
-
+
+ PacketResult
+ Handle_C (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_c (StringExtractorGDBRemote &packet, bool skip_file_pos_adjustment = false);
+
+ PacketResult
+ Handle_vCont (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vCont_actions (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_stop_reason (StringExtractorGDBRemote &packet);
+
PacketResult
Handle_vFile_Open (StringExtractorGDBRemote &packet);
@@ -318,6 +400,87 @@ protected:
PacketResult
Handle_qPlatform_shell (StringExtractorGDBRemote &packet);
+ PacketResult
+ Handle_qRegisterInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qfThreadInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qsThreadInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_p (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_P (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_H (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_interrupt (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_m (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_M (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_Z (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_z (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_s (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qSupported (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSaveRegisterState (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vAttach (StringExtractorGDBRemote &packet);
+
+ void
+ SetCurrentThreadID (lldb::tid_t tid);
+
+ lldb::tid_t
+ GetCurrentThreadID () const;
+
+ void
+ SetContinueThreadID (lldb::tid_t tid);
+
+ lldb::tid_t
+ GetContinueThreadID () const { return m_continue_tid; }
+
+ lldb_private::Error
+ SetSTDIOFileDescriptor (int fd);
+
+ static void
+ STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len);
+
private:
bool
DebugserverProcessReaped (lldb::pid_t pid);
@@ -342,6 +505,41 @@ private:
bool
KillSpawnedProcess (lldb::pid_t pid);
+ bool
+ IsGdbServer ()
+ {
+ return !m_is_platform;
+ }
+
+ /// Launch a process from lldb-gdbserver
+ lldb_private::Error
+ LaunchDebugServerProcess ();
+
+ /// Launch a process from lldb-platform
+ lldb_private::Error
+ LaunchPlatformProcess ();
+
+ void
+ HandleInferiorState_Exited (lldb_private::NativeProcessProtocol *process);
+
+ void
+ HandleInferiorState_Stopped (lldb_private::NativeProcessProtocol *process);
+
+ void
+ FlushInferiorOutput ();
+
+ lldb_private::NativeThreadProtocolSP
+ GetThreadFromSuffix (StringExtractorGDBRemote &packet);
+
+ uint32_t
+ GetNextSavedRegistersID ();
+
+ void
+ MaybeCloseInferiorTerminalConnection ();
+
+ void
+ ClearProcessSpecificData ();
+
//------------------------------------------------------------------
// For GDBRemoteCommunicationServer only
//------------------------------------------------------------------
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
index 73b9b3e8267e..6d7eca1a0ced 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -21,6 +21,7 @@
#include "lldb/Interpreter/PythonDataObjects.h"
#endif
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
#include "lldb/Utility/Utils.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
@@ -199,7 +200,7 @@ GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataE
const uint32_t prim_reg = reg_info->value_regs[idx];
if (prim_reg == LLDB_INVALID_REGNUM)
break;
- // We have a valid primordial regsiter as our constituent.
+ // We have a valid primordial register as our constituent.
// Grab the corresponding register info.
const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg);
if (prim_reg_info == NULL)
@@ -232,11 +233,20 @@ GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataE
if (&data != &m_reg_data)
{
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size);
+#endif
+ // If our register context and our register info disagree, which should never happen, don't
+ // read past the end of the buffer.
+ if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size)
+ return false;
+
// If we aren't extracting into our own buffer (which
// only happens when this function is called from
// ReadRegisterValue(uint32_t, Scalar&)) then
// we transfer bytes from our buffer into the data
// buffer that was passed in
+
data.SetByteOrder (m_reg_data.GetByteOrder());
data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size);
}
@@ -322,6 +332,16 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo *
// if (gdb_comm.IsRunning())
// return false;
+
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size);
+#endif
+
+ // If our register context and our register info disagree, which should never happen, don't
+ // overwrite past the end of the buffer.
+ if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size)
+ return false;
+
// Grab a pointer to where we are going to put this register
uint8_t *dst = const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size));
@@ -389,7 +409,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo *
const uint32_t reg = reg_info->value_regs[idx];
if (reg == LLDB_INVALID_REGNUM)
break;
- // We have a valid primordial regsiter as our constituent.
+ // We have a valid primordial register as our constituent.
// Grab the corresponding register info.
const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg);
if (value_reg_info == NULL)
@@ -502,6 +522,8 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
StringExtractorGDBRemote response;
+ const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false;
+
Mutex::Locker locker;
if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers."))
{
@@ -519,29 +541,62 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
packet_len = ::snprintf (packet, sizeof(packet), "g");
assert (packet_len < ((int)sizeof(packet) - 1));
- if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)
+ if (use_g_packet && gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)
{
- if (response.IsErrorResponse())
- return false;
-
- std::string &response_str = response.GetStringRef();
- if (isxdigit(response_str[0]))
+ int packet_len = 0;
+ if (thread_suffix_supported)
+ packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID());
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "g");
+ assert (packet_len < ((int)sizeof(packet) - 1));
+
+ if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)
{
- response_str.insert(0, 1, 'G');
- if (thread_suffix_supported)
+ if (response.IsErrorResponse())
+ return false;
+
+ std::string &response_str = response.GetStringRef();
+ if (isxdigit(response_str[0]))
{
- char thread_id_cstr[64];
- ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
- response_str.append (thread_id_cstr);
+ response_str.insert(0, 1, 'G');
+ if (thread_suffix_supported)
+ {
+ char thread_id_cstr[64];
+ ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+ response_str.append (thread_id_cstr);
+ }
+ data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size()));
+ return true;
}
- data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size()));
- return true;
}
}
+ else
+ {
+ // For the use_g_packet == false case, we're going to read each register
+ // individually and store them as binary data in a buffer instead of as ascii
+ // characters.
+ const RegisterInfo *reg_info;
+
+ // data_sp will take ownership of this DataBufferHeap pointer soon.
+ DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0));
+
+ for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++)
+ {
+ if (reg_info->value_regs) // skip registers that are slices of real registers
+ continue;
+ ReadRegisterBytes (reg_info, m_reg_data);
+ // ReadRegisterBytes saves the contents of the register in to the m_reg_data buffer
+ }
+ memcpy (reg_ctx->GetBytes(), m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize());
+
+ data_sp = reg_ctx;
+ return true;
+ }
}
}
else
{
+
Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
if (log)
{
@@ -575,6 +630,8 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+ const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false;
+
StringExtractorGDBRemote response;
Mutex::Locker locker;
if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers."))
@@ -588,63 +645,126 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
// as well.
const char *G_packet = (const char *)data_sp->GetBytes();
size_t G_packet_len = data_sp->GetByteSize();
- if (gdb_comm.SendPacketAndWaitForResponse (G_packet,
- G_packet_len,
- response,
- false) == GDBRemoteCommunication::PacketResult::Success)
+ if (use_g_packet
+ && gdb_comm.SendPacketAndWaitForResponse (G_packet,
+ G_packet_len,
+ response,
+ false) == GDBRemoteCommunication::PacketResult::Success)
{
- if (response.IsOKResponse())
- return true;
- else if (response.IsErrorResponse())
+ // The data_sp contains the entire G response packet including the
+ // G, and if the thread suffix is supported, it has the thread suffix
+ // as well.
+ const char *G_packet = (const char *)data_sp->GetBytes();
+ size_t G_packet_len = data_sp->GetByteSize();
+ if (gdb_comm.SendPacketAndWaitForResponse (G_packet,
+ G_packet_len,
+ response,
+ false) == GDBRemoteCommunication::PacketResult::Success)
{
- uint32_t num_restored = 0;
- // We need to manually go through all of the registers and
- // restore them manually
-
- response.GetStringRef().assign (G_packet, G_packet_len);
- response.SetFilePos(1); // Skip the leading 'G'
- DataBufferHeap buffer (m_reg_data.GetByteSize(), 0);
- DataExtractor restore_data (buffer.GetBytes(),
- buffer.GetByteSize(),
- m_reg_data.GetByteOrder(),
- m_reg_data.GetAddressByteSize());
-
- const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(),
- restore_data.GetByteSize(),
- '\xcc');
-
- if (bytes_extracted < restore_data.GetByteSize())
- restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder());
-
- //ReadRegisterBytes (const RegisterInfo *reg_info, RegisterValue &value, DataExtractor &data)
- const RegisterInfo *reg_info;
- // We have to march the offset of each register along in the
- // buffer to make sure we get the right offset.
- uint32_t reg_byte_offset = 0;
- for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, reg_byte_offset += reg_info->byte_size)
+ if (response.IsOKResponse())
+ return true;
+ else if (response.IsErrorResponse())
{
- const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
-
- // Skip composite registers.
- if (reg_info->value_regs)
- continue;
+ uint32_t num_restored = 0;
+ // We need to manually go through all of the registers and
+ // restore them manually
+
+ response.GetStringRef().assign (G_packet, G_packet_len);
+ response.SetFilePos(1); // Skip the leading 'G'
+
+ // G_packet_len is hex-ascii characters plus prefix 'G' plus suffix thread specifier.
+ // This means buffer will be a little more than 2x larger than necessary but we resize
+ // it down once we've extracted all hex ascii chars from the packet.
+ DataBufferHeap buffer (G_packet_len, 0);
+ DataExtractor restore_data (buffer.GetBytes(),
+ buffer.GetByteSize(),
+ m_reg_data.GetByteOrder(),
+ m_reg_data.GetAddressByteSize());
+
+ const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(),
+ restore_data.GetByteSize(),
+ '\xcc');
+
+ if (bytes_extracted < restore_data.GetByteSize())
+ restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder());
+
+ const RegisterInfo *reg_info;
+
+ // The g packet contents may either include the slice registers (registers defined in
+ // terms of other registers, e.g. eax is a subset of rax) or not. The slice registers
+ // should NOT be in the g packet, but some implementations may incorrectly include them.
+ //
+ // If the slice registers are included in the packet, we must step over the slice registers
+ // when parsing the packet -- relying on the RegisterInfo byte_offset field would be incorrect.
+ // If the slice registers are not included, then using the byte_offset values into the
+ // data buffer is the best way to find individual register values.
+
+ uint64_t size_including_slice_registers = 0;
+ uint64_t size_not_including_slice_registers = 0;
+ uint64_t size_by_highest_offset = 0;
+
+ for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx)
+ {
+ size_including_slice_registers += reg_info->byte_size;
+ if (reg_info->value_regs == NULL)
+ size_not_including_slice_registers += reg_info->byte_size;
+ if (reg_info->byte_offset >= size_by_highest_offset)
+ size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size;
+ }
- // Only write down the registers that need to be written
- // if we are going to be doing registers individually.
- bool write_reg = true;
- const uint32_t reg_byte_size = reg_info->byte_size;
+ bool use_byte_offset_into_buffer;
+ if (size_by_highest_offset == restore_data.GetByteSize())
+ {
+ // The size of the packet agrees with the highest offset: + size in the register file
+ use_byte_offset_into_buffer = true;
+ }
+ else if (size_not_including_slice_registers == restore_data.GetByteSize())
+ {
+ // The size of the packet is the same as concatenating all of the registers sequentially,
+ // skipping the slice registers
+ use_byte_offset_into_buffer = true;
+ }
+ else if (size_including_slice_registers == restore_data.GetByteSize())
+ {
+ // The slice registers are present in the packet (when they shouldn't be).
+ // Don't try to use the RegisterInfo byte_offset into the restore_data, it will
+ // point to the wrong place.
+ use_byte_offset_into_buffer = false;
+ }
+ else {
+ // None of our expected sizes match the actual g packet data we're looking at.
+ // The most conservative approach here is to use the running total byte offset.
+ use_byte_offset_into_buffer = false;
+ }
- const char *restore_src = (const char *)restore_data.PeekData(reg_byte_offset, reg_byte_size);
- if (restore_src)
+ // In case our register definitions don't include the correct offsets,
+ // keep track of the size of each reg & compute offset based on that.
+ uint32_t running_byte_offset = 0;
+ for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, running_byte_offset += reg_info->byte_size)
{
- if (GetRegisterIsValid(reg))
+ // Skip composite aka slice registers (e.g. eax is a slice of rax).
+ if (reg_info->value_regs)
+ continue;
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ uint32_t register_offset;
+ if (use_byte_offset_into_buffer)
{
- const char *current_src = (const char *)m_reg_data.PeekData(reg_byte_offset, reg_byte_size);
- if (current_src)
- write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0;
+ register_offset = reg_info->byte_offset;
+ }
+ else
+ {
+ register_offset = running_byte_offset;
}
- if (write_reg)
+ // Only write down the registers that need to be written
+ // if we are going to be doing registers individually.
+ bool write_reg = true;
+ const uint32_t reg_byte_size = reg_info->byte_size;
+
+ const char *restore_src = (const char *)restore_data.PeekData(register_offset, reg_byte_size);
+ if (restore_src)
{
StreamString packet;
packet.Printf ("P%x=", reg);
@@ -662,14 +782,88 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
response,
false) == GDBRemoteCommunication::PacketResult::Success)
{
- if (response.IsOKResponse())
- ++num_restored;
+ const char *current_src = (const char *)m_reg_data.PeekData(register_offset, reg_byte_size);
+ if (current_src)
+ write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0;
+ }
+
+ if (write_reg)
+ {
+ StreamString packet;
+ packet.Printf ("P%x=", reg);
+ packet.PutBytesAsRawHex8 (restore_src,
+ reg_byte_size,
+ lldb::endian::InlHostByteOrder(),
+ lldb::endian::InlHostByteOrder());
+
+ if (thread_suffix_supported)
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ SetRegisterIsValid(reg, false);
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ ++num_restored;
+ }
}
}
}
+ return num_restored > 0;
+ }
+ }
+ }
+ else
+ {
+ // For the use_g_packet == false case, we're going to write each register
+ // individually. The data buffer is binary data in this case, instead of
+ // ascii characters.
+
+ bool arm64_debugserver = false;
+ if (m_thread.GetProcess().get())
+ {
+ const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture();
+ if (arch.IsValid()
+ && arch.GetMachine() == llvm::Triple::aarch64
+ && arch.GetTriple().getVendor() == llvm::Triple::Apple
+ && arch.GetTriple().getOS() == llvm::Triple::IOS)
+ {
+ arm64_debugserver = true;
+ }
+ }
+ uint32_t num_restored = 0;
+ const RegisterInfo *reg_info;
+ for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++)
+ {
+ if (reg_info->value_regs) // skip registers that are slices of real registers
+ continue;
+ // Skip the fpsr and fpcr floating point status/control register writing to
+ // work around a bug in an older version of debugserver that would lead to
+ // register context corruption when writing fpsr/fpcr.
+ if (arm64_debugserver &&
+ (strcmp (reg_info->name, "fpsr") == 0 || strcmp (reg_info->name, "fpcr") == 0))
+ {
+ continue;
+ }
+ StreamString packet;
+ packet.Printf ("P%x=", reg_info->kinds[eRegisterKindLLDB]);
+ packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder());
+ if (thread_suffix_supported)
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ SetRegisterIsValid(reg_info, false);
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ ++num_restored;
}
- return num_restored > 0;
}
+ return num_restored > 0;
}
}
}
@@ -693,7 +887,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
uint32_t
-GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
{
return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num);
}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
index 38f29bbca0de..b77381458914 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -98,7 +98,7 @@ public:
WriteAllRegisterValues (const lldb_private::RegisterCheckpoint &reg_checkpoint);
virtual uint32_t
- ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
protected:
friend class ThreadGDBRemote;
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 1172222d62a4..f35d954caa7b 100644
--- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -56,11 +56,14 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Target/SystemRuntime.h"
#include "lldb/Utility/PseudoTerminal.h"
// Project includes
#include "lldb/Host/Host.h"
+#include "Plugins/Process/Utility/FreeBSDSignals.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "Plugins/Process/Utility/LinuxSignals.h"
#include "Plugins/Process/Utility/StopInfoMachException.h"
#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"
#include "Utility/StringExtractorGDBRemote.h"
@@ -166,8 +169,6 @@ namespace {
} // anonymous namespace end
-static bool rand_initialized = false;
-
// TODO Randomly assigning a port is unsafe. We should get an unused
// ephemeral port from the kernel and make sure we reserve it before passing
// it to debugserver.
@@ -180,19 +181,22 @@ static bool rand_initialized = false;
#define HIGH_PORT (49151u)
#endif
+#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
+static bool rand_initialized = false;
+
static inline uint16_t
get_random_port ()
{
if (!rand_initialized)
{
time_t seed = time(NULL);
-
+
rand_initialized = true;
srand(seed);
}
return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT;
}
-
+#endif
lldb_private::ConstString
ProcessGDBRemote::GetPluginNameStatic()
@@ -243,6 +247,7 @@ ProcessGDBRemote::CanDebug (Target &target, bool plugin_specified_by_name)
case ObjectFile::eTypeObjectFile:
case ObjectFile::eTypeSharedLibrary:
case ObjectFile::eTypeStubLibrary:
+ case ObjectFile::eTypeJIT:
return false;
case ObjectFile::eTypeExecutable:
case ObjectFile::eTypeDynamicLinker:
@@ -275,7 +280,8 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) :
m_continue_C_tids (),
m_continue_s_tids (),
m_continue_S_tids (),
- m_max_memory_size (512),
+ m_max_memory_size (0),
+ m_remote_stub_max_memory_size (0),
m_addr_to_mmap_size (),
m_thread_create_bp_sp (),
m_waiting_for_attach (false),
@@ -624,6 +630,7 @@ ProcessGDBRemote::WillAttachToProcessWithName (const char *process_name, bool wa
Error
ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
Error error (WillLaunchOrAttach ());
if (error.Fail())
@@ -674,7 +681,11 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but no stop reply packet was received", pid, remote_url);
}
- if (error.Success()
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalizing target architecture initial triple: %s (GetTarget().GetArchitecture().IsValid() %s, m_gdb_comm.GetHostArchitecture().IsValid(): %s)", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str (), GetTarget ().GetArchitecture ().IsValid () ? "true" : "false", m_gdb_comm.GetHostArchitecture ().IsValid () ? "true" : "false");
+
+
+ if (error.Success()
&& !GetTarget().GetArchitecture().IsValid()
&& m_gdb_comm.GetHostArchitecture().IsValid())
{
@@ -685,6 +696,42 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture());
}
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalized target architecture triple: %s", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str ());
+
+ // Set the Unix signals properly for the target.
+ // FIXME Add a gdb-remote packet to discover dynamically.
+ if (error.Success ())
+ {
+ const ArchSpec arch_spec = GetTarget ().GetArchitecture ();
+ if (arch_spec.IsValid ())
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": determining unix signals type based on architecture %s, triple %s", __FUNCTION__, GetID (), arch_spec.GetArchitectureName () ? arch_spec.GetArchitectureName () : "<null>", arch_spec.GetTriple ().getTriple ().c_str ());
+
+ switch (arch_spec.GetTriple ().getOS ())
+ {
+ case llvm::Triple::Linux:
+ SetUnixSignals (UnixSignalsSP (new process_linux::LinuxSignals ()));
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s using Linux unix signals type for pid %" PRIu64, __FUNCTION__, GetID ());
+ break;
+ case llvm::Triple::OpenBSD:
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::NetBSD:
+ SetUnixSignals (UnixSignalsSP (new FreeBSDSignals ()));
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s using *BSD unix signals type for pid %" PRIu64, __FUNCTION__, GetID ());
+ break;
+ default:
+ SetUnixSignals (UnixSignalsSP (new UnixSignals ()));
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s using generic unix signals type for pid %" PRIu64, __FUNCTION__, GetID ());
+ break;
+ }
+ }
+ }
+
return error;
}
@@ -710,23 +757,23 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
const char *stderr_path = NULL;
const char *working_dir = launch_info.GetWorkingDirectory();
- const ProcessLaunchInfo::FileAction *file_action;
+ const FileAction *file_action;
file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
if (file_action)
{
- if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ if (file_action->GetAction() == FileAction::eFileActionOpen)
stdin_path = file_action->GetPath();
}
file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
if (file_action)
{
- if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ if (file_action->GetAction() == FileAction::eFileActionOpen)
stdout_path = file_action->GetPath();
}
file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
if (file_action)
{
- if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ if (file_action->GetAction() == FileAction::eFileActionOpen)
stderr_path = file_action->GetPath();
}
@@ -795,9 +842,14 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
m_gdb_comm.SetSTDERR (stderr_path);
m_gdb_comm.SetDisableASLR (launch_flags & eLaunchFlagDisableASLR);
+ m_gdb_comm.SetDetachOnError (launch_flags & eLaunchFlagDetachOnError);
m_gdb_comm.SendLaunchArchPacket (m_target.GetArchitecture().GetArchitectureName());
+ const char * launch_event_data = launch_info.GetLaunchEventData();
+ if (launch_event_data != NULL && *launch_event_data != '\0')
+ m_gdb_comm.SendLaunchEventDataPacket (launch_event_data);
+
if (working_dir && working_dir[0])
{
m_gdb_comm.SetWorkingDir (working_dir);
@@ -958,7 +1010,7 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
}
void
-ProcessGDBRemote::DidLaunchOrAttach ()
+ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch)
{
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
if (log)
@@ -969,16 +1021,17 @@ ProcessGDBRemote::DidLaunchOrAttach ()
// See if the GDB server supports the qHostInfo information
- ArchSpec gdb_remote_arch = m_gdb_comm.GetHostArchitecture();
// See if the GDB server supports the qProcessInfo packet, if so
// prefer that over the Host information as it will be more specific
// to our process.
if (m_gdb_comm.GetProcessArchitecture().IsValid())
- gdb_remote_arch = m_gdb_comm.GetProcessArchitecture();
+ process_arch = m_gdb_comm.GetProcessArchitecture();
+ else
+ process_arch = m_gdb_comm.GetHostArchitecture();
- if (gdb_remote_arch.IsValid())
+ if (process_arch.IsValid())
{
ArchSpec &target_arch = GetTarget().GetArchitecture();
@@ -991,15 +1044,15 @@ ProcessGDBRemote::DidLaunchOrAttach ()
// it has, so we really need to take the remote host architecture as our
// defacto architecture in this case.
- if (gdb_remote_arch.GetMachine() == llvm::Triple::arm &&
- gdb_remote_arch.GetTriple().getVendor() == llvm::Triple::Apple)
+ if (process_arch.GetMachine() == llvm::Triple::arm &&
+ process_arch.GetTriple().getVendor() == llvm::Triple::Apple)
{
- target_arch = gdb_remote_arch;
+ GetTarget().SetArchitecture (process_arch);
}
else
{
// Fill in what is missing in the triple
- const llvm::Triple &remote_triple = gdb_remote_arch.GetTriple();
+ const llvm::Triple &remote_triple = process_arch.GetTriple();
llvm::Triple &target_triple = target_arch.GetTriple();
if (target_triple.getVendorName().size() == 0)
{
@@ -1019,7 +1072,7 @@ ProcessGDBRemote::DidLaunchOrAttach ()
{
// The target doesn't have a valid architecture yet, set it from
// the architecture we got from the remote GDB server
- target_arch = gdb_remote_arch;
+ GetTarget().SetArchitecture (process_arch);
}
}
}
@@ -1028,7 +1081,8 @@ ProcessGDBRemote::DidLaunchOrAttach ()
void
ProcessGDBRemote::DidLaunch ()
{
- DidLaunchOrAttach ();
+ ArchSpec process_arch;
+ DidLaunchOrAttach (process_arch);
}
Error
@@ -1063,6 +1117,8 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process
if (error.Success())
{
+ m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError());
+
char packet[64];
const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid);
SetID (attach_pid);
@@ -1100,6 +1156,8 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const Pro
{
StreamString packet;
+ m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError());
+
if (attach_info.GetWaitForLaunch())
{
if (!m_gdb_comm.GetVAttachOrWaitSupported())
@@ -1135,9 +1193,11 @@ ProcessGDBRemote::SetExitStatus (int exit_status, const char *cstr)
}
void
-ProcessGDBRemote::DidAttach ()
+ProcessGDBRemote::DidAttach (ArchSpec &process_arch)
{
- DidLaunchOrAttach ();
+ // If you can figure out what the architecture is, fill it in here.
+ process_arch.Clear();
+ DidLaunchOrAttach (process_arch);
}
@@ -1452,8 +1512,7 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new
if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
log->Printf(
"ProcessGDBRemote::%s Making new thread: %p for thread ID: 0x%" PRIx64 ".\n",
- __FUNCTION__,
- thread_sp.get(),
+ __FUNCTION__, static_cast<void*>(thread_sp.get()),
thread_sp->GetID());
}
else
@@ -1461,8 +1520,7 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new
if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
log->Printf(
"ProcessGDBRemote::%s Found old thread: %p for thread ID: 0x%" PRIx64 ".\n",
- __FUNCTION__,
- thread_sp.get(),
+ __FUNCTION__, static_cast<void*>(thread_sp.get()),
thread_sp->GetID());
}
new_thread_list.AddThread(thread_sp);
@@ -1557,9 +1615,9 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
log->Printf ("ProcessGDBRemote::%s Adding new thread: %p for thread ID: 0x%" PRIx64 ".\n",
__FUNCTION__,
- thread_sp.get(),
+ static_cast<void*>(thread_sp.get()),
thread_sp->GetID());
-
+
m_thread_list_real.AddThread(thread_sp);
}
gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get());
@@ -1582,7 +1640,6 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
if (tid != LLDB_INVALID_THREAD_ID)
m_thread_ids.push_back (tid);
value.erase(0, comma_pos + 1);
-
}
tid = Args::StringToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
if (tid != LLDB_INVALID_THREAD_ID)
@@ -1709,7 +1766,6 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
thread_sp->SetStopInfo (invalid_stop_info_sp);
}
}
-
}
else if (reason.compare("trap") == 0)
{
@@ -1734,7 +1790,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
handled = true;
}
}
-
+
if (!handled && signo && did_exec == false)
{
if (signo == SIGTRAP)
@@ -1744,7 +1800,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
handled = true;
addr_t pc = thread_sp->GetRegisterContext()->GetPC() + m_breakpoint_pc_offset;
lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
-
+
if (bp_site_sp)
{
// If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
@@ -1776,7 +1832,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
if (!handled)
thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo));
}
-
+
if (!description.empty())
{
lldb::StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());
@@ -1796,6 +1852,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
break;
case 'W':
+ case 'X':
// process exited
return eStateExited;
@@ -1864,10 +1921,6 @@ ProcessGDBRemote::DoDetach(bool keep_stopped)
if (log)
log->Printf ("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped);
- DisableAllBreakpointSites ();
-
- m_thread_list.DiscardThreadPlans();
-
error = m_gdb_comm.Detach (keep_stopped);
if (log)
{
@@ -1928,7 +1981,7 @@ ProcessGDBRemote::DoDestroy ()
if (m_destroy_tried_resuming)
{
if (log)
- log->PutCString ("ProcessGDBRemote::DoDestroy()Tried resuming to destroy once already, not doing it again.");
+ log->PutCString ("ProcessGDBRemote::DoDestroy() - Tried resuming to destroy once already, not doing it again.");
}
else
{
@@ -2064,7 +2117,7 @@ ProcessGDBRemote::DoDestroy ()
else
{
if (log)
- log->Printf ("ProcessGDBRemote::DoDestroy - failed to send k packet");
+ log->Printf ("ProcessGDBRemote::DoDestroy - killed or interrupted while attaching");
exit_string.assign ("killed or interrupted while attaching.");
}
}
@@ -2124,6 +2177,7 @@ ProcessGDBRemote::GetImageInfoAddress()
size_t
ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error)
{
+ GetMaxMemorySize ();
if (size > m_max_memory_size)
{
// Keep memory read sizes down to a sane limit. This function will be
@@ -2133,7 +2187,16 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro
}
char packet[64];
- const int packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size);
+ int packet_len;
+ bool binary_memory_read = m_gdb_comm.GetxPacketSupported();
+ if (binary_memory_read)
+ {
+ packet_len = ::snprintf (packet, sizeof(packet), "x0x%" PRIx64 ",0x%" PRIx64, (uint64_t)addr, (uint64_t)size);
+ }
+ else
+ {
+ packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size);
+ }
assert (packet_len + 1 < (int)sizeof(packet));
StringExtractorGDBRemote response;
if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true) == GDBRemoteCommunication::PacketResult::Success)
@@ -2141,7 +2204,25 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro
if (response.IsNormalResponse())
{
error.Clear();
- return response.GetHexBytes(buf, size, '\xdd');
+ if (binary_memory_read)
+ {
+ // The lower level GDBRemoteCommunication packet receive layer has already de-quoted any
+ // 0x7d character escaping that was present in the packet
+
+ size_t data_received_size = response.GetBytesLeft();
+ if (data_received_size > size)
+ {
+ // Don't write past the end of BUF if the remote debug server gave us too
+ // much data for some reason.
+ data_received_size = size;
+ }
+ memcpy (buf, response.GetStringRef().data(), data_received_size);
+ return data_received_size;
+ }
+ else
+ {
+ return response.GetHexBytes(buf, size, '\xdd');
+ }
}
else if (response.IsErrorResponse())
error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, addr);
@@ -2160,6 +2241,7 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro
size_t
ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
{
+ GetMaxMemorySize ();
if (size > m_max_memory_size)
{
// Keep memory read sizes down to a sane limit. This function will be
@@ -2196,6 +2278,7 @@ ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Erro
lldb::addr_t
ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &error)
{
+ lldb_private::Log *log (lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_EXPRESSIONS));
addr_t allocated_addr = LLDB_INVALID_ADDRESS;
LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
@@ -2221,7 +2304,11 @@ ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &er
eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0))
m_addr_to_mmap_size[allocated_addr] = size;
else
+ {
allocated_addr = LLDB_INVALID_ADDRESS;
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s no direct stub support for memory allocation, and InferiorCallMmap also failed - is stub missing register context save/restore capability?", __FUNCTION__);
+ }
break;
}
@@ -2393,7 +2480,7 @@ ProcessGDBRemote::EnableBreakpointSite (BreakpointSite *bp_site)
return error;
}
- // We will reach here when the stub gives an unsported response to a hardware breakpoint
+ // We will reach here when the stub gives an unsupported response to a hardware breakpoint
if (log)
log->Printf("Hardware breakpoints are unsupported");
@@ -2440,8 +2527,16 @@ ProcessGDBRemote::DisableBreakpointSite (BreakpointSite *bp_site)
break;
case BreakpointSite::eExternal:
- if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false, addr, bp_op_size))
+ {
+ GDBStoppointType stoppoint_type;
+ if (bp_site->IsHardware())
+ stoppoint_type = eBreakpointHardware;
+ else
+ stoppoint_type = eBreakpointSoftware;
+
+ if (m_gdb_comm.SendGDBStoppointTypePacket(stoppoint_type, false, addr, bp_op_size))
error.SetErrorToGenericError();
+ }
break;
}
if (error.Success())
@@ -2602,9 +2697,9 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info
debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false);
debugserver_launch_info.SetUserID(process_info.GetUserID());
-#if defined (__APPLE__) && defined (__arm__)
+#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__))
// On iOS, still do a local connection using a random port
- const char *hostname = "localhost";
+ const char *hostname = "127.0.0.1";
uint16_t port = get_random_port ();
#else
// Set hostname being NULL to do the reverse connect where debugserver
@@ -2918,13 +3013,33 @@ ProcessGDBRemote::AsyncThread (void *arg)
break;
case eStateExited:
+ {
process->SetLastStopPacket (response);
process->ClearThreadIDList();
response.SetFilePos(1);
- process->SetExitStatus(response.GetHexU8(), NULL);
+
+ int exit_status = response.GetHexU8();
+ const char *desc_cstr = NULL;
+ StringExtractor extractor;
+ std::string desc_string;
+ if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';')
+ {
+ std::string desc_token;
+ while (response.GetNameColonValue (desc_token, desc_string))
+ {
+ if (desc_token == "description")
+ {
+ extractor.GetStringRef().swap(desc_string);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (desc_string);
+ desc_cstr = desc_string.c_str();
+ }
+ }
+ }
+ process->SetExitStatus(exit_status, desc_cstr);
done = true;
break;
-
+ }
case eStateInvalid:
process->SetExitStatus(-1, "lost connection");
break;
@@ -3060,6 +3175,146 @@ ProcessGDBRemote::GetDynamicLoader ()
return m_dyld_ap.get();
}
+Error
+ProcessGDBRemote::SendEventData(const char *data)
+{
+ int return_value;
+ bool was_supported;
+
+ Error error;
+
+ return_value = m_gdb_comm.SendLaunchEventDataPacket (data, &was_supported);
+ if (return_value != 0)
+ {
+ if (!was_supported)
+ error.SetErrorString("Sending events is not supported for this process.");
+ else
+ error.SetErrorStringWithFormat("Error sending event data: %d.", return_value);
+ }
+ return error;
+}
+
+const DataBufferSP
+ProcessGDBRemote::GetAuxvData()
+{
+ DataBufferSP buf;
+ if (m_gdb_comm.GetQXferAuxvReadSupported())
+ {
+ std::string response_string;
+ if (m_gdb_comm.SendPacketsAndConcatenateResponses("qXfer:auxv:read::", response_string) == GDBRemoteCommunication::PacketResult::Success)
+ buf.reset(new DataBufferHeap(response_string.c_str(), response_string.length()));
+ }
+ return buf;
+}
+
+StructuredData::ObjectSP
+ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid)
+{
+ StructuredData::ObjectSP object_sp;
+
+ if (m_gdb_comm.GetThreadExtendedInfoSupported())
+ {
+ StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
+ SystemRuntime *runtime = GetSystemRuntime();
+ if (runtime)
+ {
+ runtime->AddThreadExtendedInfoPacketHints (args_dict);
+ }
+ args_dict->GetAsDictionary()->AddIntegerItem ("thread", tid);
+
+ StreamString packet;
+ packet << "jThreadExtendedInfo:";
+ args_dict->Dump (packet);
+
+ // FIXME the final character of a JSON dictionary, '}', is the escape
+ // character in gdb-remote binary mode. lldb currently doesn't escape
+ // these characters in its packet output -- so we add the quoted version
+ // of the } character here manually in case we talk to a debugserver which
+ // un-escapes the characters at packet read time.
+ packet << (char) (0x7d ^ 0x20);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType();
+ if (response_type == StringExtractorGDBRemote::eResponse)
+ {
+ if (!response.Empty())
+ {
+ // The packet has already had the 0x7d xor quoting stripped out at the
+ // GDBRemoteCommunication packet receive level.
+ object_sp = StructuredData::ParseJSON (response.GetStringRef());
+ }
+ }
+ }
+ }
+ return object_sp;
+}
+
+// Establish the largest memory read/write payloads we should use.
+// If the remote stub has a max packet size, stay under that size.
+//
+// If the remote stub's max packet size is crazy large, use a
+// reasonable largeish default.
+//
+// If the remote stub doesn't advertise a max packet size, use a
+// conservative default.
+
+void
+ProcessGDBRemote::GetMaxMemorySize()
+{
+ const uint64_t reasonable_largeish_default = 128 * 1024;
+ const uint64_t conservative_default = 512;
+
+ if (m_max_memory_size == 0)
+ {
+ uint64_t stub_max_size = m_gdb_comm.GetRemoteMaxPacketSize();
+ if (stub_max_size != UINT64_MAX && stub_max_size != 0)
+ {
+ // Save the stub's claimed maximum packet size
+ m_remote_stub_max_memory_size = stub_max_size;
+
+ // Even if the stub says it can support ginormous packets,
+ // don't exceed our reasonable largeish default packet size.
+ if (stub_max_size > reasonable_largeish_default)
+ {
+ stub_max_size = reasonable_largeish_default;
+ }
+
+ m_max_memory_size = stub_max_size;
+ }
+ else
+ {
+ m_max_memory_size = conservative_default;
+ }
+ }
+}
+
+void
+ProcessGDBRemote::SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max)
+{
+ if (user_specified_max != 0)
+ {
+ GetMaxMemorySize ();
+
+ if (m_remote_stub_max_memory_size != 0)
+ {
+ if (m_remote_stub_max_memory_size < user_specified_max)
+ {
+ m_max_memory_size = m_remote_stub_max_memory_size; // user specified a packet size too big, go as big
+ // as the remote stub says we can go.
+ }
+ else
+ {
+ m_max_memory_size = user_specified_max; // user's packet size is good
+ }
+ }
+ else
+ {
+ m_max_memory_size = user_specified_max; // user's packet size is probably fine
+ }
+ }
+}
class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed
{
@@ -3101,6 +3356,53 @@ public:
}
};
+class CommandObjectProcessGDBRemotePacketXferSize : public CommandObjectParsed
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacketXferSize(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process plugin packet xfer-size",
+ "Maximum size that lldb will try to read/write one one chunk.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectProcessGDBRemotePacketXferSize ()
+ {
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ result.AppendErrorWithFormat ("'%s' takes an argument to specify the max amount to be transferred when reading/writing", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ const char *packet_size = command.GetArgumentAtIndex(0);
+ errno = 0;
+ uint64_t user_specified_max = strtoul (packet_size, NULL, 10);
+ if (errno == 0 && user_specified_max != 0)
+ {
+ process->SetUserSpecifiedMaxMemoryTransferSize (user_specified_max);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+};
+
+
class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed
{
private:
@@ -3226,6 +3528,7 @@ public:
LoadSubCommand ("history", CommandObjectSP (new CommandObjectProcessGDBRemotePacketHistory (interpreter)));
LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessGDBRemotePacketSend (interpreter)));
LoadSubCommand ("monitor", CommandObjectSP (new CommandObjectProcessGDBRemotePacketMonitor (interpreter)));
+ LoadSubCommand ("xfer-size", CommandObjectSP (new CommandObjectProcessGDBRemotePacketXferSize (interpreter)));
}
~CommandObjectProcessGDBRemotePacket ()
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 9331775bb896..942b31c84dde 100644
--- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -23,7 +23,9 @@
#include "lldb/Core/Error.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/StringList.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/lldb-private-forward.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"
@@ -113,7 +115,7 @@ public:
const lldb_private::ProcessAttachInfo &attach_info);
virtual void
- DidAttach ();
+ DidAttach (lldb_private::ArchSpec &process_arch);
//------------------------------------------------------------------
// PluginInterface protocol
@@ -221,12 +223,17 @@ public:
return m_gdb_comm;
}
+ virtual lldb_private::Error
+ SendEventData(const char *data);
+
//----------------------------------------------------------------------
// Override SetExitStatus so we can disconnect from the remote GDB server
//----------------------------------------------------------------------
virtual bool
SetExitStatus (int exit_status, const char *cstr);
+ void
+ SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max);
protected:
friend class ThreadGDBRemote;
@@ -299,6 +306,15 @@ protected:
bool
ParseRegisters(lldb_private::ScriptInterpreterObject *registers_array);
+ const lldb::DataBufferSP
+ GetAuxvData() override;
+
+ lldb_private::StructuredData::ObjectSP
+ GetExtendedInfoForThread (lldb::tid_t tid);
+
+ void
+ GetMaxMemorySize();
+
//------------------------------------------------------------------
/// Broadcaster event bits definitions.
//------------------------------------------------------------------
@@ -334,14 +350,15 @@ protected:
tid_sig_collection m_continue_C_tids; // 'C' for continue with signal
tid_collection m_continue_s_tids; // 's' for step
tid_sig_collection m_continue_S_tids; // 'S' for step with signal
- size_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory
+ uint64_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory
+ uint64_t m_remote_stub_max_memory_size; // The maximum memory size the remote gdb stub can handle
MMapMap m_addr_to_mmap_size;
lldb::BreakpointSP m_thread_create_bp_sp;
bool m_waiting_for_attach;
bool m_destroy_tried_resuming;
lldb::CommandObjectSP m_command_sp;
int64_t m_breakpoint_pc_offset;
-
+
bool
StartAsyncThread ();
@@ -368,7 +385,7 @@ protected:
UpdateThreadIDList ();
void
- DidLaunchOrAttach ();
+ DidLaunchOrAttach (lldb_private::ArchSpec& process_arch);
lldb_private::Error
ConnectToDebugserver (const char *host_port);
diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
index fb524deda813..5c70cb5427cb 100644
--- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
+++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
@@ -107,6 +107,58 @@ ThreadGDBRemote::GetQueueID ()
return LLDB_INVALID_QUEUE_ID;
}
+QueueSP
+ThreadGDBRemote::GetQueue ()
+{
+ queue_id_t queue_id = GetQueueID();
+ QueueSP queue;
+ if (queue_id != LLDB_INVALID_QUEUE_ID)
+ {
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ queue = process_sp->GetQueueList().FindQueueByID (queue_id);
+ }
+ }
+ return queue;
+}
+
+addr_t
+ThreadGDBRemote::GetQueueLibdispatchQueueAddress ()
+{
+ addr_t dispatch_queue_t_addr = LLDB_INVALID_ADDRESS;
+ if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ SystemRuntime *runtime = process_sp->GetSystemRuntime ();
+ if (runtime)
+ {
+ dispatch_queue_t_addr = runtime->GetLibdispatchQueueAddressFromThreadQAddress (m_thread_dispatch_qaddr);
+ }
+ }
+ }
+ return dispatch_queue_t_addr;
+}
+
+StructuredData::ObjectSP
+ThreadGDBRemote::FetchThreadExtendedInfo ()
+{
+ StructuredData::ObjectSP object_sp;
+ const lldb::user_id_t tid = GetProtocolID();
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD));
+ if (log)
+ log->Printf ("Fetching extended information for thread %4.4" PRIx64, tid);
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
+ object_sp = gdb_process->GetExtendedInfoForThread (tid);
+ }
+ return object_sp;
+}
+
void
ThreadGDBRemote::WillResume (StateType resume_state)
{
diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
index dd4cc036ef8b..a204a917ecb3 100644
--- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
+++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
@@ -12,6 +12,7 @@
#include <string>
+#include "lldb/Core/StructuredData.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"
@@ -41,6 +42,12 @@ public:
virtual lldb::queue_id_t
GetQueueID ();
+ virtual lldb::QueueSP
+ GetQueue ();
+
+ lldb::addr_t
+ GetQueueLibdispatchQueueAddress ();
+
virtual lldb::RegisterContextSP
GetRegisterContext ();
@@ -80,6 +87,9 @@ public:
m_thread_dispatch_qaddr = thread_dispatch_qaddr;
}
+ lldb_private::StructuredData::ObjectSP
+ FetchThreadExtendedInfo ();
+
protected:
friend class ProcessGDBRemote;
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp
index ff2e3762556a..bc2e7a62b76e 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp
@@ -92,84 +92,6 @@ DWARFAbbreviationDeclaration::IsValid()
}
-void
-DWARFAbbreviationDeclaration::CopyExcludingAddressAttributes(const DWARFAbbreviationDeclaration& abbr_decl, const uint32_t idx)
-{
- m_code = abbr_decl.Code(); // Invalidate the code since that can't be copied safely.
- m_tag = abbr_decl.Tag();
- m_has_children = abbr_decl.HasChildren();
-
- const DWARFAttribute::collection& attributes = abbr_decl.Attributes();
- const uint32_t num_abbr_decl_attributes = attributes.size();
-
- dw_attr_t attr;
- dw_form_t form;
- uint32_t i;
-
- for (i = 0; i < num_abbr_decl_attributes; ++i)
- {
- attributes[i].get(attr, form);
- switch (attr)
- {
- case DW_AT_location:
- case DW_AT_frame_base:
- // Only add these if they are location expressions (have a single
- // value) and not location lists (have a lists of location
- // expressions which are only valid over specific address ranges)
- if (DWARFFormValue::IsBlockForm(form))
- m_attributes.push_back(DWARFAttribute(attr, form));
- break;
-
- case DW_AT_low_pc:
- case DW_AT_high_pc:
- case DW_AT_ranges:
- case DW_AT_entry_pc:
- // Don't add these attributes
- if (i >= idx)
- break;
- // Fall through and add attribute
- default:
- // Add anything that isn't address related
- m_attributes.push_back(DWARFAttribute(attr, form));
- break;
- }
- }
-}
-
-void
-DWARFAbbreviationDeclaration::CopyChangingStringToStrp(
- const DWARFAbbreviationDeclaration& abbr_decl,
- const DWARFDataExtractor& debug_info_data,
- dw_offset_t debug_info_offset,
- const DWARFCompileUnit* cu,
- const uint32_t strp_min_len
-)
-{
- m_code = InvalidCode;
- m_tag = abbr_decl.Tag();
- m_has_children = abbr_decl.HasChildren();
-
- const DWARFAttribute::collection& attributes = abbr_decl.Attributes();
- const uint32_t num_abbr_decl_attributes = attributes.size();
-
- dw_attr_t attr;
- dw_form_t form;
- uint32_t i;
- lldb::offset_t offset = debug_info_offset;
-
- for (i = 0; i < num_abbr_decl_attributes; ++i)
- {
- attributes[i].get(attr, form);
- dw_offset_t attr_offset = offset;
- DWARFFormValue::SkipValue(form, debug_info_data, &offset, cu);
-
- if (form == DW_FORM_string && ((offset - attr_offset) >= strp_min_len))
- m_attributes.push_back(DWARFAttribute(attr, DW_FORM_strp));
- else
- m_attributes.push_back(DWARFAttribute(attr, form));
- }
-}
-
uint32_t
DWARFAbbreviationDeclaration::FindAttributeIndex(dw_attr_t attr) const
@@ -193,19 +115,3 @@ DWARFAbbreviationDeclaration::operator == (const DWARFAbbreviationDeclaration& r
&& Attributes() == rhs.Attributes();
}
-#if 0
-DWARFAbbreviationDeclaration::Append(BinaryStreamBuf& out_buff) const
-{
- out_buff.Append32_as_ULEB128(Code());
- out_buff.Append32_as_ULEB128(Tag());
- out_buff.Append8(HasChildren());
- const uint32_t kNumAttributes = m_attributes.size();
- for (uint32_t i = 0; i < kNumAttributes; ++i)
- {
- out_buff.Append32_as_ULEB128(m_attributes[i].attr());
- out_buff.Append32_as_ULEB128(m_attributes[i].form());
- }
- out_buff.Append8(0); // Output a zero for attr (faster than using Append32_as_ULEB128)
- out_buff.Append8(0); // Output a zero for attr (faster than using Append32_as_ULEB128)
-}
-#endif // 0
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h
index 48b9ebe37ee7..0ef153a704cd 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h
+++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h
@@ -55,21 +55,12 @@ public:
{
return m_attributes[idx].get_form();
}
- void CopyExcludingAddressAttributes(const DWARFAbbreviationDeclaration& abbr_decl, const uint32_t idx);
- void CopyChangingStringToStrp(
- const DWARFAbbreviationDeclaration& abbr_decl,
- const lldb_private::DWARFDataExtractor& debug_info_data,
- dw_offset_t debug_info_offset,
- const DWARFCompileUnit* cu,
- const uint32_t strp_min_len);
uint32_t FindAttributeIndex(dw_attr_t attr) const;
bool Extract(const lldb_private::DWARFDataExtractor& data, lldb::offset_t *offset_ptr);
bool Extract(const lldb_private::DWARFDataExtractor& data, lldb::offset_t *offset_ptr, dw_uleb128_t code);
-// void Append(BinaryStreamBuf& out_buff) const;
bool IsValid();
void Dump(lldb_private::Stream *s) const;
bool operator == (const DWARFAbbreviationDeclaration& rhs) const;
-// DWARFAttribute::collection& Attributes() { return m_attributes; }
const DWARFAttribute::collection& Attributes() const { return m_attributes; }
protected:
dw_uleb128_t m_code;
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
index cf664db28acd..b2e64ad9f8c8 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
@@ -265,12 +265,16 @@ DWARFCompileUnit::ExtractDIEsIfNeeded (bool cu_die_only)
DWARFDebugInfoEntry::collection exact_size_die_array (m_die_array.begin(), m_die_array.end());
exact_size_die_array.swap (m_die_array);
}
- Log *log (LogChannelDWARF::GetLogIfAll (DWARF_LOG_DEBUG_INFO | DWARF_LOG_VERBOSE));
- if (log)
+ Log *verbose_log (LogChannelDWARF::GetLogIfAll (DWARF_LOG_DEBUG_INFO | DWARF_LOG_VERBOSE));
+ if (verbose_log)
{
StreamString strm;
- DWARFDebugInfoEntry::DumpDIECollection (strm, m_die_array);
- log->PutCString (strm.GetString().c_str());
+ Dump(&strm);
+ if (m_die_array.empty())
+ strm.Printf("error: no DIE for compile unit");
+ else
+ m_die_array[0].Dump(m_dwarf2Data, this, strm, UINT32_MAX);
+ verbose_log->PutCString (strm.GetString().c_str());
}
return m_die_array.size();
@@ -357,18 +361,43 @@ DWARFCompileUnit::SetDefaultAddressSize(uint8_t addr_size)
void
DWARFCompileUnit::BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data,
- DWARFDebugAranges* debug_aranges,
- bool clear_dies_if_already_not_parsed)
+ DWARFDebugAranges* debug_aranges)
{
// This function is usually called if there in no .debug_aranges section
// in order to produce a compile unit level set of address ranges that
- // is accurate. If the DIEs weren't parsed, then we don't want all dies for
- // all compile units to stay loaded when they weren't needed. So we can end
- // up parsing the DWARF and then throwing them all away to keep memory usage
- // down.
+ // is accurate.
+
+ // First get the compile unit DIE only and check if it has a DW_AT_ranges
+ const DWARFDebugInfoEntry* die = GetCompileUnitDIEOnly();
+
+ const dw_offset_t cu_offset = GetOffset();
+ if (die)
+ {
+ DWARFDebugRanges::RangeList ranges;
+ const size_t num_ranges = die->GetAttributeAddressRanges(dwarf2Data, this, ranges, false);
+ if (num_ranges > 0)
+ {
+ // This compile unit has DW_AT_ranges, assume this is correct if it
+ // is present since clang no longer makes .debug_aranges by default
+ // and it emits DW_AT_ranges for DW_TAG_compile_units. GCC also does
+ // this with recent GCC builds.
+ for (size_t i=0; i<num_ranges; ++i)
+ {
+ const DWARFDebugRanges::RangeList::Entry &range = ranges.GetEntryRef(i);
+ debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), range.GetRangeEnd());
+ }
+
+ return; // We got all of our ranges from the DW_AT_ranges attribute
+ }
+ }
+ // We don't have a DW_AT_ranges attribute, so we need to parse the DWARF
+
+ // If the DIEs weren't parsed, then we don't want all dies for all compile units
+ // to stay loaded when they weren't needed. So we can end up parsing the DWARF
+ // and then throwing them all away to keep memory usage down.
const bool clear_dies = ExtractDIEsIfNeeded (false) > 1;
- const DWARFDebugInfoEntry* die = DIE();
+ die = DIE();
if (die)
die->BuildAddressRangeTable(dwarf2Data, this, debug_aranges);
@@ -393,7 +422,7 @@ DWARFCompileUnit::BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data,
for (uint32_t idx=0; idx<num_ranges; ++idx)
{
const LineTable::FileAddressRanges::Entry &range = file_ranges.GetEntryRef(idx);
- debug_aranges->AppendRange(GetOffset(), range.GetRangeBase(), range.GetRangeEnd());
+ debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), range.GetRangeEnd());
printf ("0x%8.8x: [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", GetOffset(), range.GetRangeBase(), range.GetRangeEnd());
}
}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
index 35597f389423..ed1894b8a9f6 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
+++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
@@ -54,8 +54,7 @@ public:
dw_addr_t GetBaseAddress() const { return m_base_addr; }
void ClearDIEs(bool keep_compile_unit_die);
void BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data,
- DWARFDebugAranges* debug_aranges,
- bool clear_dies_if_already_not_parsed);
+ DWARFDebugAranges* debug_aranges);
void
SetBaseAddress(dw_addr_t base_addr)
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
index d083f8a615c4..b0b71368b800 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
@@ -188,38 +188,74 @@ DWARFDebugArangeSet::Extract(const DWARFDataExtractor &data, lldb::offset_t *off
m_header.cu_offset = data.GetDWARFOffset(offset_ptr);
m_header.addr_size = data.GetU8(offset_ptr);
m_header.seg_size = data.GetU8(offset_ptr);
-
-
- // The first tuple following the header in each set begins at an offset
- // that is a multiple of the size of a single tuple (that is, twice the
- // size of an address). The header is padded, if necessary, to the
- // appropriate boundary.
- const uint32_t header_size = *offset_ptr - m_offset;
- const uint32_t tuple_size = m_header.addr_size << 1;
- uint32_t first_tuple_offset = 0;
- while (first_tuple_offset < header_size)
- first_tuple_offset += tuple_size;
-
- *offset_ptr = m_offset + first_tuple_offset;
-
- Descriptor arangeDescriptor;
-
- assert(sizeof(arangeDescriptor.address) == sizeof(arangeDescriptor.length));
- assert(sizeof(arangeDescriptor.address) >= m_header.addr_size);
-
- while (data.ValidOffset(*offset_ptr))
+
+ // Try to avoid reading invalid arange sets by making sure:
+ // 1 - the version looks good
+ // 2 - the address byte size looks plausible
+ // 3 - the length seems to make sense
+ // size looks plausible
+ if ((m_header.version >= 2 && m_header.version <= 5) &&
+ (m_header.addr_size == 4 || m_header.addr_size == 8) &&
+ (m_header.length > 0))
{
- arangeDescriptor.address = data.GetMaxU64(offset_ptr, m_header.addr_size);
- arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size);
-
- // Each set of tuples is terminated by a 0 for the address and 0
- // for the length.
- if (arangeDescriptor.address || arangeDescriptor.length)
- m_arange_descriptors.push_back(arangeDescriptor);
+ if (data.ValidOffset(m_offset + sizeof(m_header.length) + m_header.length - 1))
+ {
+ // The first tuple following the header in each set begins at an offset
+ // that is a multiple of the size of a single tuple (that is, twice the
+ // size of an address). The header is padded, if necessary, to the
+ // appropriate boundary.
+ const uint32_t header_size = *offset_ptr - m_offset;
+ const uint32_t tuple_size = m_header.addr_size << 1;
+ uint32_t first_tuple_offset = 0;
+ while (first_tuple_offset < header_size)
+ first_tuple_offset += tuple_size;
+
+ *offset_ptr = m_offset + first_tuple_offset;
+
+ Descriptor arangeDescriptor;
+
+ static_assert(sizeof(arangeDescriptor.address) == sizeof(arangeDescriptor.length),
+ "DWARFDebugArangeSet::Descriptor.address and DWARFDebugArangeSet::Descriptor.length must have same size");
+
+ while (data.ValidOffset(*offset_ptr))
+ {
+ arangeDescriptor.address = data.GetMaxU64(offset_ptr, m_header.addr_size);
+ arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size);
+
+ // Each set of tuples is terminated by a 0 for the address and 0
+ // for the length.
+ if (arangeDescriptor.address || arangeDescriptor.length)
+ m_arange_descriptors.push_back(arangeDescriptor);
+ else
+ break; // We are done if we get a zero address and length
+ }
+ }
+#if defined (LLDB_CONFIGURATION_DEBUG)
else
- break; // We are done if we get a zero address and length
+ {
+ printf ("warning: .debug_arange set length is too large arange data at 0x%8.8x: length=0x%8.8x, version=0x%4.4x, cu_offset=0x%8.8x, addr_size=%u, seg_size=%u\n",
+ m_offset,
+ m_header.length,
+ m_header.version,
+ m_header.cu_offset,
+ m_header.addr_size,
+ m_header.seg_size);
+ }
+#endif
}
-
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ else
+ {
+ printf ("warning: .debug_arange set has bad header at 0x%8.8x: length=0x%8.8x, version=0x%4.4x, cu_offset=0x%8.8x, addr_size=%u, seg_size=%u\n",
+ m_offset,
+ m_header.length,
+ m_header.version,
+ m_header.cu_offset,
+ m_header.addr_size,
+ m_header.seg_size);
+ }
+#endif
+
return !m_arange_descriptors.empty();
}
return false;
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
index 4f77bff86bdc..60e5c6ed62fe 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
@@ -93,14 +93,13 @@ DWARFDebugAranges::Generate(SymbolFileDWARF* dwarf2Data)
DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
if (debug_info)
{
- const bool clear_dies_if_already_not_parsed = true;
uint32_t cu_idx = 0;
const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
{
DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
if (cu)
- cu->BuildAddressRangeTable(dwarf2Data, this, clear_dies_if_already_not_parsed);
+ cu->BuildAddressRangeTable(dwarf2Data, this);
}
}
return !IsEmpty();
@@ -136,7 +135,7 @@ void
DWARFDebugAranges::Sort (bool minimize)
{
Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p",
- __PRETTY_FUNCTION__, this);
+ __PRETTY_FUNCTION__, static_cast<void*>(this));
Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES));
size_t orig_arange_size = 0;
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
index d4db12c17a40..a8c553e2d2ca 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -79,7 +79,6 @@ DWARFDebugInfo::GetCompileUnitAranges ()
// Manually build arange data for everything that wasn't in the .debug_aranges table.
bool printed = false;
const size_t num_compile_units = GetNumCompileUnits();
- const bool clear_dies_if_already_not_parsed = true;
for (size_t idx = 0; idx < num_compile_units; ++idx)
{
DWARFCompileUnit* cu = GetCompileUnitAtIndex(idx);
@@ -94,7 +93,7 @@ DWARFDebugInfo::GetCompileUnitAranges ()
m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str());
printed = true;
}
- cu->BuildAddressRangeTable (m_dwarf2Data, m_cu_aranges_ap.get(), clear_dies_if_already_not_parsed);
+ cu->BuildAddressRangeTable (m_dwarf2Data, m_cu_aranges_ap.get());
}
}
@@ -214,13 +213,6 @@ DWARFDebugInfo::ContainsCompileUnit (const DWARFCompileUnit *cu) const
return false;
}
-
-static bool CompileUnitOffsetLessThan (const DWARFCompileUnitSP& a, const DWARFCompileUnitSP& b)
-{
- return a->GetOffset() < b->GetOffset();
-}
-
-
static int
CompareDWARFCompileUnitSPOffset (const void *key, const void *arrmem)
{
@@ -280,15 +272,6 @@ DWARFDebugInfo::GetCompileUnitContainingDIE(dw_offset_t die_offset)
}
//----------------------------------------------------------------------
-// Compare function DWARFDebugAranges::Range structures
-//----------------------------------------------------------------------
-static bool CompareDIEOffset (const DWARFDebugInfoEntry& die1, const DWARFDebugInfoEntry& die2)
-{
- return die1.GetOffset() < die2.GetOffset();
-}
-
-
-//----------------------------------------------------------------------
// GetDIE()
//
// Get the DIE (Debug Information Entry) with the specified offset.
@@ -341,40 +324,6 @@ DWARFDebugInfo::GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUn
}
//----------------------------------------------------------------------
-// DWARFDebugInfo_ParseCallback
-//
-// A callback function for the static DWARFDebugInfo::Parse() function
-// that gets parses all compile units and DIE's into an internate
-// representation for further modification.
-//----------------------------------------------------------------------
-
-static dw_offset_t
-DWARFDebugInfo_ParseCallback
-(
- SymbolFileDWARF* dwarf2Data,
- DWARFCompileUnitSP& cu_sp,
- DWARFDebugInfoEntry* die,
- const dw_offset_t next_offset,
- const uint32_t curr_depth,
- void* userData
-)
-{
- DWARFDebugInfo* debug_info = (DWARFDebugInfo*)userData;
- DWARFCompileUnit* cu = cu_sp.get();
- if (die)
- {
- cu->AddDIE(*die);
- }
- else if (cu)
- {
- debug_info->AddCompileUnit(cu_sp);
- }
-
- // Just return the current offset to parse the next CU or DIE entry
- return next_offset;
-}
-
-//----------------------------------------------------------------------
// AddCompileUnit
//----------------------------------------------------------------------
void
@@ -563,7 +512,7 @@ static dw_offset_t DumpCallback
// We have already found our DIE and are printing it's children. Obey
// our recurse depth and return an invalid offset if we get done
- // dumping all the the children
+ // dumping all of the children
if (dumpInfo->recurse_depth == UINT32_MAX || curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth)
die->Dump(dwarf2Data, cu, *s, 0);
}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
index 37741eb1da9c..856a7fa7a2ff 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -1485,6 +1485,40 @@ DWARFDebugInfoEntry::GetAttributeAddressRange
hi_pc = fail_value;
return false;
}
+
+size_t
+DWARFDebugInfoEntry::GetAttributeAddressRanges(SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugRanges::RangeList &ranges,
+ bool check_hi_lo_pc) const
+{
+ ranges.Clear();
+
+ dw_offset_t ranges_offset = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_ranges, DW_INVALID_OFFSET);
+ if (ranges_offset != DW_INVALID_OFFSET)
+ {
+ dw_offset_t debug_ranges_offset = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_ranges, DW_INVALID_OFFSET);
+ if (debug_ranges_offset != DW_INVALID_OFFSET)
+ {
+ DWARFDebugRanges* debug_ranges = dwarf2Data->DebugRanges();
+
+ debug_ranges->FindRanges(debug_ranges_offset, ranges);
+ ranges.Slide (cu->GetBaseAddress());
+ }
+ }
+ else if (check_hi_lo_pc)
+ {
+ dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;
+ dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;
+ if (GetAttributeAddressRange (dwarf2Data, cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS))
+ {
+ if (lo_pc < hi_pc)
+ ranges.Append(DWARFDebugRanges::RangeList::Entry(lo_pc, hi_pc - lo_pc));
+ }
+ }
+ return ranges.GetSize();
+}
+
//----------------------------------------------------------------------
// GetAttributeValueAsLocation
//
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
index f74057555286..3949ad339dd8 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
@@ -86,7 +86,7 @@ public:
dw_form_t form;
};
- typedef llvm::SmallVector<Info, 32> collection;
+ typedef llvm::SmallVector<Info, 8> collection;
collection m_infos;
};
@@ -209,7 +209,13 @@ public:
dw_addr_t& lo_pc,
dw_addr_t& hi_pc,
uint64_t fail_value) const;
-
+
+ size_t GetAttributeAddressRanges (
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugRanges::RangeList &ranges,
+ bool check_hi_lo_pc) const;
+
dw_offset_t GetAttributeValueAsLocation(
SymbolFileDWARF* dwarf2Data,
const DWARFCompileUnit* cu,
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
index 0a2f1f749409..6a2649463b54 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
@@ -256,7 +256,13 @@ DWARFDebugLine::DumpStatementOpcodes(Log *log, const DWARFDataExtractor& debug_l
prologue.file_names.push_back(fileEntry);
}
break;
-
+
+ case DW_LNE_set_discriminator:
+ {
+ uint64_t discriminator = debug_line_data.GetULEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNE_set_discriminator (0x%" PRIx64 ")", op_offset, discriminator);
+ }
+ break;
default:
log->Printf( "0x%8.8x: DW_LNE_??? (%2.2x) - Skipping unknown upcode", op_offset, opcode);
// Length doesn't include the zero opcode byte or the length itself, but
@@ -412,7 +418,7 @@ DWARFDebugLine::ParsePrologue(const DWARFDataExtractor& debug_line_data, lldb::o
const char * s;
prologue->total_length = debug_line_data.GetDWARFInitialLength(offset_ptr);
prologue->version = debug_line_data.GetU16(offset_ptr);
- if (prologue->version != 2)
+ if (prologue->version < 2 || prologue->version > 3)
return false;
prologue->prologue_length = debug_line_data.GetDWARFOffset(offset_ptr);
@@ -480,7 +486,7 @@ DWARFDebugLine::ParseSupportFiles (const lldb::ModuleSP &module_sp,
(void)debug_line_data.GetDWARFInitialLength(&offset);
const char * s;
uint32_t version = debug_line_data.GetU16(&offset);
- if (version != 2)
+ if (version < 2 || version > 3)
return false;
const dw_offset_t end_prologue_offset = debug_line_data.GetDWARFOffset(&offset) + offset;
@@ -666,7 +672,7 @@ DWARFDebugLine::ParseStatementTable
// The files are numbered, starting at 1, in the order in which they
// appear; the names in the prologue come before names defined by
// the DW_LNE_define_file instruction. These numbers are used in the
- // the file register of the state machine.
+ // file register of the state machine.
{
FileNameEntry fileEntry;
fileEntry.name = debug_line_data.GetCStr(offset_ptr);
@@ -789,7 +795,7 @@ DWARFDebugLine::ParseStatementTable
// as a multiple of LEB128 operands for each opcode.
{
uint8_t i;
- assert (opcode - 1 < prologue->standard_opcode_lengths.size());
+ assert (static_cast<size_t>(opcode - 1) < prologue->standard_opcode_lengths.size());
const uint8_t opcode_length = prologue->standard_opcode_lengths[opcode - 1];
for (i=0; i<opcode_length; ++i)
debug_line_data.Skip_LEB128(offset_ptr);
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
index 06ac825e0d4d..488e9820b6fa 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
@@ -66,11 +66,12 @@ DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF* dwarf2Data)
{
Timer scoped_timer (__PRETTY_FUNCTION__,
"DWARFDebugPubnames::GeneratePubnames (data = %p)",
- dwarf2Data);
+ static_cast<void*>(dwarf2Data));
Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES));
if (log)
- log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)", dwarf2Data);
+ log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)",
+ static_cast<void*>(dwarf2Data));
m_sets.clear();
DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
index daa3b0aa6666..0953554ffd7d 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
@@ -143,7 +143,7 @@ DWARFDebugRanges::Dump(Stream &s, const DWARFDataExtractor& debug_ranges_data, l
{
dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
- // Extend 4 byte addresses that consits of 32 bits of 1's to be 64 bits
+ // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits
// of ones
if (begin == 0xFFFFFFFFull && addr_size == 4)
begin = LLDB_INVALID_ADDRESS;
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
index abf69190c93c..5512072529fc 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
@@ -78,7 +78,7 @@ DWARFDeclContext::operator==(const DWARFDeclContext& rhs) const
collection::const_iterator rhs_begin = rhs.m_entries.begin();
// The two entry arrays have the same size
- // First compare the tags before we do expensize name compares
+ // First compare the tags before we do expensive name compares
for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos)
{
if (pos->tag != rhs_pos->tag)
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
index abd273770ddc..ab8e68ab5516 100644
--- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
+++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
@@ -133,7 +133,7 @@ DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* off
case DW_FORM_data8: m_value.value.uval = data.GetU64(offset_ptr); break;
case DW_FORM_string: m_value.value.cstr = data.GetCStr(offset_ptr);
// Set the string value to also be the data for inlined cstr form values only
- // so we can tell the differnence between DW_FORM_string and DW_FORM_strp form
+ // so we can tell the difference between DW_FORM_string and DW_FORM_strp form
// values;
m_value.data = (uint8_t*)m_value.value.cstr; break;
case DW_FORM_exprloc:
diff --git a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h
index 44a24f2756ad..ab0c37beeac9 100644
--- a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h
+++ b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h
@@ -169,7 +169,7 @@ struct DWARFMappedHash
{
if (return_implementation_only_if_available)
{
- // We found the one true definiton for this class, so
+ // We found the one true definition for this class, so
// only return that
die_offsets.clear();
die_offsets.push_back (die_info_array[i].offset);
@@ -388,7 +388,7 @@ struct DWARFMappedHash
}
size_t
- GetMinumumHashDataByteSize () const
+ GetMinimumHashDataByteSize () const
{
return min_hash_data_byte_size;
}
@@ -465,7 +465,7 @@ struct DWARFMappedHash
break;
default:
- // We can always skip atomes we don't know about
+ // We can always skip atoms we don't know about
break;
}
}
@@ -651,11 +651,11 @@ struct DWARFMappedHash
}
const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
- const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize();
+ const size_t min_total_hash_data_size = count * m_header.header_data.GetMinimumHashDataByteSize();
if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
{
// We have at least one HashData entry, and we have enough
- // data to parse at leats "count" HashData enties.
+ // data to parse at least "count" HashData entries.
// First make sure the entire C string matches...
const bool match = strcmp (name, strp_cstr) == 0;
@@ -678,7 +678,7 @@ struct DWARFMappedHash
DIEInfo die_info;
if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
{
- // Only happend the HashData if the string matched...
+ // Only happened if the HashData of the string matched...
if (match)
pair.value.push_back (die_info);
}
@@ -724,7 +724,7 @@ struct DWARFMappedHash
return eResultError;
const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
- const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize();
+ const size_t min_total_hash_data_size = count * m_header.header_data.GetMinimumHashDataByteSize();
if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
{
const bool match = regex.Execute(strp_cstr);
@@ -747,7 +747,7 @@ struct DWARFMappedHash
DIEInfo die_info;
if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
{
- // Only happend the HashData if the string matched...
+ // Only happened if the HashData of the string matched...
if (match)
pair.value.push_back (die_info);
}
diff --git a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
index c9ffa9ec781f..fbbc03c94625 100644
--- a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
+++ b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
@@ -18,7 +18,7 @@ using namespace lldb;
using namespace lldb_private;
-// when the one and only logging channel is abled, then this will be non NULL.
+// when the one and only logging channel is enabled, then this will be non NULL.
static LogChannelDWARF* g_log_channel = NULL;
LogChannelDWARF::LogChannelDWARF () :
@@ -103,6 +103,7 @@ LogChannelDWARF::Disable (const char **categories, Stream *feedback_strm)
else if (::strcasecmp (arg, "lookups") == 0) flag_bits &= ~DWARF_LOG_LOOKUPS;
else if (::strcasecmp (arg, "map") == 0) flag_bits &= ~DWARF_LOG_DEBUG_MAP;
else if (::strcasecmp (arg, "default") == 0) flag_bits &= ~DWARF_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "verbose") == 0) flag_bits &= ~DWARF_LOG_VERBOSE;
else if (::strncasecmp(arg, "comp", 4) == 0) flag_bits &= ~DWARF_LOG_TYPE_COMPLETION;
else
{
@@ -151,6 +152,7 @@ LogChannelDWARF::Enable
else if (::strcasecmp (arg, "lookups") == 0) flag_bits |= DWARF_LOG_LOOKUPS;
else if (::strcasecmp (arg, "map") == 0) flag_bits |= DWARF_LOG_DEBUG_MAP;
else if (::strcasecmp (arg, "default") == 0) flag_bits |= DWARF_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "verbose") == 0) flag_bits |= DWARF_LOG_VERBOSE;
else if (::strncasecmp(arg, "comp", 4) == 0) flag_bits |= DWARF_LOG_TYPE_COMPLETION;
else
{
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index c1aecfe8eb62..842260dbc3ba 100644
--- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -66,6 +66,9 @@
#include <map>
+#include <ctype.h>
+#include <string.h>
+
//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN
#ifdef ENABLE_DEBUG_PRINTF
@@ -110,7 +113,35 @@ DW_ACCESS_to_AccessType (uint32_t dwarf_accessibility)
return eAccessNone;
}
-#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE)
+static const char*
+removeHostnameFromPathname(const char* path_from_dwarf)
+{
+ if (!path_from_dwarf || !path_from_dwarf[0])
+ {
+ return path_from_dwarf;
+ }
+
+ const char *colon_pos = strchr(path_from_dwarf, ':');
+ if (!colon_pos)
+ {
+ return path_from_dwarf;
+ }
+
+ // check whether we have a windows path, and so the first character
+ // is a drive-letter not a hostname.
+ if (
+ colon_pos == path_from_dwarf + 1 &&
+ isalpha(*path_from_dwarf) &&
+ strlen(path_from_dwarf) > 2 &&
+ '\\' == path_from_dwarf[2])
+ {
+ return path_from_dwarf;
+ }
+
+ return colon_pos + 1;
+}
+
+#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE)
class DIEStack
{
@@ -525,7 +556,7 @@ SymbolFileDWARF::GetClangASTContext ()
if (!m_is_external_ast_source)
{
m_is_external_ast_source = true;
- llvm::OwningPtr<clang::ExternalASTSource> ast_source_ap (
+ llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source_ap (
new ClangExternalASTSourceCallbacks (SymbolFileDWARF::CompleteTagDecl,
SymbolFileDWARF::CompleteObjCInterfaceDecl,
SymbolFileDWARF::FindExternalVisibleDeclsByName,
@@ -829,7 +860,8 @@ SymbolFileDWARF::DebugInfo()
{
if (m_info.get() == NULL)
{
- Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+ Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p",
+ __PRETTY_FUNCTION__, static_cast<void*>(this));
if (get_debug_info_data().GetByteSize() > 0)
{
m_info.reset(new DWARFDebugInfo());
@@ -879,7 +911,8 @@ SymbolFileDWARF::DebugRanges()
{
if (m_ranges.get() == NULL)
{
- Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+ Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p",
+ __PRETTY_FUNCTION__, static_cast<void*>(this));
if (get_debug_ranges_data().GetByteSize() > 0)
{
m_ranges.reset(new DWARFDebugRanges());
@@ -943,7 +976,11 @@ SymbolFileDWARF::ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx)
}
else
{
+ // DWARF2/3 suggests the form hostname:pathname for compilation directory.
+ // Remove the host part if present.
+ cu_comp_dir = removeHostnameFromPathname(cu_comp_dir);
std::string fullpath(cu_comp_dir);
+
if (*fullpath.rbegin() != '/')
fullpath += '/';
fullpath += cu_die_name;
@@ -1170,6 +1207,11 @@ SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpec
if (cu_die)
{
const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_comp_dir, NULL);
+
+ // DWARF2/3 suggests the form hostname:pathname for compilation directory.
+ // Remove the host part if present.
+ cu_comp_dir = removeHostnameFromPathname(cu_comp_dir);
+
dw_offset_t stmt_list = cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_stmt_list, DW_INVALID_OFFSET);
// All file indexes in DWARF are one based and a file of index zero is
@@ -1983,7 +2025,7 @@ SymbolFileDWARF::ParseChildMembers
const uint64_t word_width = 32;
// Objective-C has invalid DW_AT_bit_offset values in older versions
- // of clang, so we have to be careful and only insert unnammed bitfields
+ // of clang, so we have to be careful and only insert unnamed bitfields
// if we have a new enough clang.
bool detect_unnamed_bitfields = true;
@@ -2380,7 +2422,6 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
// The type will get resolved when all of the calls to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition
// are done.
m_forward_decl_clang_type_to_die.erase (clang_type_no_qualifiers.GetOpaqueQualType());
-
// Disable external storage for this type so we don't get anymore
// clang::ExternalASTSource queries for this type.
@@ -2395,14 +2436,11 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION));
if (log)
- {
GetObjectFile()->GetModule()->LogMessageVerboseBacktrace (log,
"0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...",
MakeUserID(die->GetOffset()),
DW_TAG_value_to_name(tag),
type->GetName().AsCString());
-
- }
assert (clang_type);
DWARFDebugInfoEntry::Attributes attributes;
@@ -2413,11 +2451,10 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
case DW_TAG_class_type:
{
LayoutInfo layout_info;
-
+
{
if (die->HasChildren())
{
-
LanguageType class_language = eLanguageTypeUnknown;
if (clang_type.IsObjCObjectOrInterfaceType())
{
@@ -2426,7 +2463,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
// the class is created.
clang_type.StartTagDeclarationDefinition ();
}
-
+
int tag_decl_kind = -1;
AccessType default_accessibility = eAccessNone;
if (tag == DW_TAG_structure_type)
@@ -2444,14 +2481,14 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
tag_decl_kind = clang::TTK_Class;
default_accessibility = eAccessPrivate;
}
-
+
SymbolContext sc(GetCompUnitForDWARFCompUnit(dwarf_cu));
std::vector<clang::CXXBaseSpecifier *> base_classes;
std::vector<int> member_accessibilities;
bool is_a_class = false;
// Parse members and base classes first
DWARFDIECollection member_function_dies;
-
+
DelayedPropertyList delayed_properties;
ParseChildMembers (sc,
dwarf_cu,
@@ -2465,7 +2502,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
default_accessibility,
is_a_class,
layout_info);
-
+
// Now parse any methods if there were any...
size_t num_functions = member_function_dies.Size();
if (num_functions > 0)
@@ -2475,13 +2512,12 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
ResolveType(dwarf_cu, member_function_dies.GetDIEPtrAtIndex(i));
}
}
-
+
if (class_language == eLanguageTypeObjC)
{
ConstString class_name (clang_type.GetTypeName());
if (class_name)
{
-
DIEArray method_die_offsets;
if (m_using_apple_tables)
{
@@ -2492,21 +2528,21 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
{
if (!m_indexed)
Index ();
-
+
m_objc_class_selectors_index.Find (class_name, method_die_offsets);
}
-
+
if (!method_die_offsets.empty())
{
DWARFDebugInfo* debug_info = DebugInfo();
-
+
DWARFCompileUnit* method_cu = NULL;
const size_t num_matches = method_die_offsets.size();
for (size_t i=0; i<num_matches; ++i)
{
const dw_offset_t die_offset = method_die_offsets[i];
DWARFDebugInfoEntry *method_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &method_cu);
-
+
if (method_die)
ResolveType (method_cu, method_die);
else
@@ -2519,14 +2555,14 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
}
}
}
-
+
for (DelayedPropertyList::iterator pi = delayed_properties.begin(), pe = delayed_properties.end();
pi != pe;
++pi)
pi->Finalize();
}
}
-
+
// If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we
// need to tell the clang type it is actually a class.
if (class_language != eLanguageTypeObjC)
@@ -2534,7 +2570,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
if (is_a_class && tag_decl_kind != clang::TTK_Class)
clang_type.SetTagTypeKind (clang::TTK_Class);
}
-
+
// Since DW_TAG_structure_type gets used for both classes
// and structures, we may need to set any DW_TAG_member
// fields to have a "private" access if none was specified.
@@ -2553,7 +2589,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
&member_accessibilities.front(),
member_accessibilities.size());
}
-
+
if (!base_classes.empty())
{
// Make sure all base classes refer to complete types and not
@@ -2580,7 +2616,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
// is complete. If we don't do this, clang will crash when we
// call setBases() inside of "clang_type.SetBaseClassesForClassType()"
// below. Since we provide layout assistance, all ivars in this
- // class and other classe will be fine, this is the best we can do
+ // class and other classes will be fine, this is the best we can do
// short of crashing.
base_class_type.StartTagDeclarationDefinition ();
base_class_type.CompleteTagDeclarationDefinition ();
@@ -2589,7 +2625,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
}
clang_type.SetBaseClassesForClassType (&base_classes.front(),
base_classes.size());
-
+
// Clang will copy each CXXBaseSpecifier in "base_classes"
// so we have to free them all.
ClangASTType::DeleteBaseClassSpecifiers (&base_classes.front(),
@@ -2597,10 +2633,10 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
}
}
}
-
+
clang_type.BuildIndirectFields ();
clang_type.CompleteTagDeclarationDefinition ();
-
+
if (!layout_info.field_offsets.empty() ||
!layout_info.base_offsets.empty() ||
!layout_info.vbase_offsets.empty() )
@@ -2609,7 +2645,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
layout_info.bit_size = type->GetByteSize() * 8;
if (layout_info.bit_size == 0)
layout_info.bit_size = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_byte_size, 0) * 8;
-
+
clang::CXXRecordDecl *record_decl = clang_type.GetAsCXXRecordDecl();
if (record_decl)
{
@@ -2617,14 +2653,14 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
{
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) caching layout info for record_decl = %p, bit_size = %" PRIu64 ", alignment = %" PRIu64 ", field_offsets[%u], base_offsets[%u], vbase_offsets[%u])",
- clang_type.GetOpaqueQualType(),
- record_decl,
+ static_cast<void*>(clang_type.GetOpaqueQualType()),
+ static_cast<void*>(record_decl),
layout_info.bit_size,
layout_info.alignment,
- (uint32_t)layout_info.field_offsets.size(),
- (uint32_t)layout_info.base_offsets.size(),
- (uint32_t)layout_info.vbase_offsets.size());
-
+ static_cast<uint32_t>(layout_info.field_offsets.size()),
+ static_cast<uint32_t>(layout_info.base_offsets.size()),
+ static_cast<uint32_t>(layout_info.vbase_offsets.size()));
+
uint32_t idx;
{
llvm::DenseMap <const clang::FieldDecl *, uint64_t>::const_iterator pos, end = layout_info.field_offsets.end();
@@ -2632,13 +2668,13 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
{
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) field[%u] = { bit_offset=%u, name='%s' }",
- clang_type.GetOpaqueQualType(),
+ static_cast<void*>(clang_type.GetOpaqueQualType()),
idx,
- (uint32_t)pos->second,
+ static_cast<uint32_t>(pos->second),
pos->first->getNameAsString().c_str());
}
}
-
+
{
llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits>::const_iterator base_pos, base_end = layout_info.base_offsets.end();
for (idx = 0, base_pos = layout_info.base_offsets.begin(); base_pos != base_end; ++base_pos, ++idx)
@@ -2657,9 +2693,9 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
{
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) vbase[%u] = { byte_offset=%u, name='%s' }",
- clang_type.GetOpaqueQualType(),
+ static_cast<void*>(clang_type.GetOpaqueQualType()),
idx,
- (uint32_t)vbase_pos->second.getQuantity(),
+ static_cast<uint32_t>(vbase_pos->second.getQuantity()),
vbase_pos->first->getNameAsString().c_str());
}
}
@@ -2755,9 +2791,8 @@ SymbolFileDWARF::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_
{
Timer scoped_timer(__PRETTY_FUNCTION__,
"SymbolFileDWARF::ResolveSymbolContext (so_addr = { section = %p, offset = 0x%" PRIx64 " }, resolve_scope = 0x%8.8x)",
- so_addr.GetSection().get(),
- so_addr.GetOffset(),
- resolve_scope);
+ static_cast<void*>(so_addr.GetSection().get()),
+ so_addr.GetOffset(), resolve_scope);
uint32_t resolved = 0;
if (resolve_scope & ( eSymbolContextCompUnit |
eSymbolContextFunction |
@@ -3086,7 +3121,7 @@ SymbolFileDWARF::DIEIsInNamespace (const ClangNamespaceDecl *namespace_decl,
DWARFCompileUnit* cu,
const DWARFDebugInfoEntry* die)
{
- // No namespace specified, so the answesr i
+ // No namespace specified, so the answer is
if (namespace_decl == NULL)
return true;
@@ -3116,7 +3151,7 @@ SymbolFileDWARF::DIEIsInNamespace (const ClangNamespaceDecl *namespace_decl,
{
// We have a namespace_decl that was not NULL but it contained
// a NULL "clang::NamespaceDecl", so this means the global namespace
- // So as long the the contained decl context DIE isn't a namespace
+ // So as long the contained decl context DIE isn't a namespace
// we should be ok.
if (decl_ctx_die->Tag() != DW_TAG_namespace)
return true;
@@ -3134,18 +3169,15 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat
Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
if (log)
- {
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF::FindGlobalVariables (name=\"%s\", namespace_decl=%p, append=%u, max_matches=%u, variables)",
name.GetCString(),
- namespace_decl,
- append,
- max_matches);
- }
-
+ static_cast<const void*>(namespace_decl),
+ append, max_matches);
+
if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl))
return 0;
-
+
DWARFDebugInfo* info = DebugInfo();
if (info == NULL)
return 0;
@@ -3159,7 +3191,7 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat
const uint32_t original_size = variables.GetSize();
DIEArray die_offsets;
-
+
if (m_using_apple_tables)
{
if (m_apple_names_ap.get())
@@ -3167,10 +3199,10 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat
const char *name_cstr = name.GetCString();
const char *base_name_start;
const char *base_name_end = NULL;
-
+
if (!CPPLanguageRuntime::StripNamespacesFromVariableName(name_cstr, base_name_start, base_name_end))
base_name_start = name_cstr;
-
+
m_apple_names_ap->FindByName (base_name_start, die_offsets);
}
}
@@ -3182,14 +3214,14 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat
m_global_index.Find (name, die_offsets);
}
-
+
const size_t num_die_matches = die_offsets.size();
if (num_die_matches)
{
SymbolContext sc;
sc.module_sp = m_obj_file->GetModule();
assert (sc.module_sp);
-
+
DWARFDebugInfo* debug_info = DebugInfo();
DWARFCompileUnit* dwarf_cu = NULL;
const DWARFDebugInfoEntry* die = NULL;
@@ -3209,11 +3241,11 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat
case DW_TAG_try_block:
case DW_TAG_catch_block:
break;
-
+
case DW_TAG_variable:
{
sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX);
-
+
if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
continue;
@@ -3242,10 +3274,9 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat
{
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF::FindGlobalVariables (name=\"%s\", namespace_decl=%p, append=%u, max_matches=%u, variables) => %u",
- name.GetCString(),
- namespace_decl,
- append,
- max_matches,
+ name.GetCString(),
+ static_cast<const void*>(namespace_decl),
+ append, max_matches,
num_matches);
}
return num_matches;
@@ -3255,13 +3286,12 @@ uint32_t
SymbolFileDWARF::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
{
Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
-
+
if (log)
{
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF::FindGlobalVariables (regex=\"%s\", append=%u, max_matches=%u, variables)",
- regex.GetText(),
- append,
+ regex.GetText(), append,
max_matches);
}
@@ -3959,38 +3989,32 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc,
return 0;
Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
-
+
if (log)
{
if (namespace_decl)
- {
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(%p) \"%s\", append=%u, max_matches=%u, type_list)",
name.GetCString(),
- namespace_decl->GetNamespaceDecl(),
+ static_cast<void*>(namespace_decl->GetNamespaceDecl()),
namespace_decl->GetQualifiedName().c_str(),
- append,
- max_matches);
- }
+ append, max_matches);
else
- {
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(NULL), append=%u, max_matches=%u, type_list)",
- name.GetCString(),
- append,
+ name.GetCString(), append,
max_matches);
- }
}
// If we aren't appending the results to this list, then clear the list
if (!append)
types.Clear();
-
+
if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl))
return 0;
DIEArray die_offsets;
-
+
if (m_using_apple_tables)
{
if (m_apple_types_ap.get())
@@ -4003,10 +4027,10 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc,
{
if (!m_indexed)
Index ();
-
+
m_type_index.Find (name, die_offsets);
}
-
+
const size_t num_die_matches = die_offsets.size();
if (num_die_matches)
@@ -4024,7 +4048,7 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc,
{
if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
continue;
-
+
Type *matching_type = ResolveType (dwarf_cu, die);
if (matching_type)
{
@@ -4052,10 +4076,9 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc,
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(%p) \"%s\", append=%u, max_matches=%u, type_list) => %u",
name.GetCString(),
- namespace_decl->GetNamespaceDecl(),
+ static_cast<void*>(namespace_decl->GetNamespaceDecl()),
namespace_decl->GetQualifiedName().c_str(),
- append,
- max_matches,
+ append, max_matches,
num_matches);
}
else
@@ -4063,8 +4086,7 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc,
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(NULL), append=%u, max_matches=%u, type_list) => %u",
name.GetCString(),
- append,
- max_matches,
+ append, max_matches,
num_matches);
}
}
@@ -4156,7 +4178,7 @@ SymbolFileDWARF::FindNamespace (const SymbolContext& sc,
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF::FindNamespace (sc, name=\"%s\") => clang::NamespaceDecl(%p) \"%s\"",
name.GetCString(),
- namespace_decl.GetNamespaceDecl(),
+ static_cast<const void*>(namespace_decl.GetNamespaceDecl()),
namespace_decl.GetQualifiedName().c_str());
}
@@ -4203,8 +4225,8 @@ SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc,
TypeList* type_list,
std::vector<ClangASTType>& function_param_types,
std::vector<clang::ParmVarDecl*>& function_param_decls,
- unsigned &type_quals,
- ClangASTContext::TemplateParameterInfos &template_param_infos)
+ unsigned &type_quals) // ,
+ // ClangASTContext::TemplateParameterInfos &template_param_infos))
{
if (parent_die == NULL)
return 0;
@@ -4357,7 +4379,11 @@ SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc,
case DW_TAG_template_type_parameter:
case DW_TAG_template_value_parameter:
- ParseTemplateDIE (dwarf_cu, die,template_param_infos);
+ // The one caller of this was never using the template_param_infos,
+ // and the local variable was taking up a large amount of stack space
+ // in SymbolFileDWARF::ParseType() so this was removed. If we ever need
+ // the template params back, we can add them back.
+ // ParseTemplateDIE (dwarf_cu, die, template_param_infos);
break;
default:
@@ -4618,20 +4644,20 @@ SymbolFileDWARF::ResolveNamespaceDIE (DWARFCompileUnit *dwarf_cu, const DWARFDeb
{
GetObjectFile()->GetModule()->LogMessage (log,
"ASTContext => %p: 0x%8.8" PRIx64 ": DW_TAG_namespace with DW_AT_name(\"%s\") => clang::NamespaceDecl *%p (original = %p)",
- GetClangASTContext().getASTContext(),
+ static_cast<void*>(GetClangASTContext().getASTContext()),
MakeUserID(die->GetOffset()),
namespace_name,
- namespace_decl,
- namespace_decl->getOriginalNamespace());
+ static_cast<void*>(namespace_decl),
+ static_cast<void*>(namespace_decl->getOriginalNamespace()));
}
else
{
GetObjectFile()->GetModule()->LogMessage (log,
"ASTContext => %p: 0x%8.8" PRIx64 ": DW_TAG_namespace (anonymous) => clang::NamespaceDecl *%p (original = %p)",
- GetClangASTContext().getASTContext(),
+ static_cast<void*>(GetClangASTContext().getASTContext()),
MakeUserID(die->GetOffset()),
- namespace_decl,
- namespace_decl->getOriginalNamespace());
+ static_cast<void*>(namespace_decl),
+ static_cast<void*>(namespace_decl->getOriginalNamespace()));
}
}
@@ -4982,7 +5008,7 @@ SymbolFileDWARF::DIEDeclContextsMatch (DWARFCompileUnit* cu1, const DWARFDebugIn
if (count1 != count2)
return false;
- // Make sure the DW_TAG values match all the way back up the the
+ // Make sure the DW_TAG values match all the way back up the
// compile unit. If they don't, then we are done.
const DWARFDebugInfoEntry *decl_ctx_die1;
const DWARFDebugInfoEntry *decl_ctx_die2;
@@ -5084,7 +5110,7 @@ SymbolFileDWARF::FindDefinitionTypeForDIE (DWARFCompileUnit* cu,
GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTagAndQualifiedNameHash()");
m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash (type_name.GetCString(), die->Tag(), qualified_name_hash, die_offsets);
}
- else if (has_tag > 1)
+ else if (has_tag)
{
if (log)
GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTag()");
@@ -5388,7 +5414,7 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
const DWARFDebugInfoEntry *src_class_die,
DWARFCompileUnit* dst_cu,
const DWARFDebugInfoEntry *dst_class_die,
- llvm::SmallVectorImpl <const DWARFDebugInfoEntry *> &failures)
+ DWARFDIECollection &failures)
{
if (!class_type || !src_cu || !src_class_die || !dst_cu || !dst_class_die)
return false;
@@ -5456,7 +5482,7 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
// Is everything kosher so we can go through the members at top speed?
bool fast_path = true;
-
+
if (src_size != dst_size)
{
if (src_size != 0 && dst_size != 0)
@@ -5468,12 +5494,12 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
src_size,
dst_size);
}
-
+
fast_path = false;
}
uint32_t idx;
-
+
if (fast_path)
{
for (idx = 0; idx < src_size; ++idx)
@@ -5493,10 +5519,10 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
DW_TAG_value_to_name(src_die->Tag()));
fast_path = false;
}
-
+
const char *src_name = src_die->GetMangledName (src_symfile, src_cu);
const char *dst_name = dst_die->GetMangledName (this, dst_cu);
-
+
// Make sure the names match
if (src_name == dst_name || (strcmp (src_name, dst_name) == 0))
continue;
@@ -5509,7 +5535,7 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
src_name,
dst_die->GetOffset(),
dst_name);
-
+
fast_path = false;
}
}
@@ -5523,25 +5549,31 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
{
src_die = src_name_to_die.GetValueAtIndexUnchecked (idx);
dst_die = dst_name_to_die.GetValueAtIndexUnchecked (idx);
-
+
clang::DeclContext *src_decl_ctx = src_symfile->m_die_to_decl_ctx[src_die];
if (src_decl_ctx)
{
if (log)
- log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset());
+ log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x",
+ static_cast<void*>(src_decl_ctx),
+ src_die->GetOffset(), dst_die->GetOffset());
LinkDeclContextToDIE (src_decl_ctx, dst_die);
}
else
{
if (log)
- log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
+ log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found",
+ src_die->GetOffset(), dst_die->GetOffset());
}
-
+
Type *src_child_type = m_die_to_type[src_die];
if (src_child_type)
{
if (log)
- log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset());
+ log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x",
+ static_cast<void*>(src_child_type),
+ src_child_type->GetID(),
+ src_die->GetOffset(), dst_die->GetOffset());
m_die_to_type[dst_die] = src_child_type;
}
else
@@ -5556,24 +5588,27 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
// We must do this slowly. For each member of the destination, look
// up a member in the source with the same name, check its tag, and
// unique them if everything matches up. Report failures.
-
+
if (!src_name_to_die.IsEmpty() && !dst_name_to_die.IsEmpty())
{
src_name_to_die.Sort();
-
+
for (idx = 0; idx < dst_size; ++idx)
{
const char *dst_name = dst_name_to_die.GetCStringAtIndex(idx);
dst_die = dst_name_to_die.GetValueAtIndexUnchecked(idx);
src_die = src_name_to_die.Find(dst_name, NULL);
-
+
if (src_die && (src_die->Tag() == dst_die->Tag()))
{
clang::DeclContext *src_decl_ctx = src_symfile->m_die_to_decl_ctx[src_die];
if (src_decl_ctx)
{
if (log)
- log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset());
+ log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x",
+ static_cast<void*>(src_decl_ctx),
+ src_die->GetOffset(),
+ dst_die->GetOffset());
LinkDeclContextToDIE (src_decl_ctx, dst_die);
}
else
@@ -5581,12 +5616,16 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
if (log)
log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
}
-
+
Type *src_child_type = m_die_to_type[src_die];
if (src_child_type)
{
if (log)
- log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset());
+ log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x",
+ static_cast<void*>(src_child_type),
+ src_child_type->GetID(),
+ src_die->GetOffset(),
+ dst_die->GetOffset());
m_die_to_type[dst_die] = src_child_type;
}
else
@@ -5600,7 +5639,7 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
if (log)
log->Printf ("warning: couldn't find a match for 0x%8.8x", dst_die->GetOffset());
- failures.push_back(dst_die);
+ failures.Append(dst_die);
}
}
}
@@ -5614,13 +5653,13 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
if (src_size_artificial && dst_size_artificial)
{
dst_name_to_die_artificial.Sort();
-
+
for (idx = 0; idx < src_size_artificial; ++idx)
{
const char *src_name_artificial = src_name_to_die_artificial.GetCStringAtIndex(idx);
src_die = src_name_to_die_artificial.GetValueAtIndexUnchecked (idx);
dst_die = dst_name_to_die_artificial.Find(src_name_artificial, NULL);
-
+
if (dst_die)
{
// Both classes have the artificial types, link them
@@ -5628,7 +5667,9 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
if (src_decl_ctx)
{
if (log)
- log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset());
+ log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x",
+ static_cast<void*>(src_decl_ctx),
+ src_die->GetOffset(), dst_die->GetOffset());
LinkDeclContextToDIE (src_decl_ctx, dst_die);
}
else
@@ -5636,12 +5677,15 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
if (log)
log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
}
-
+
Type *src_child_type = m_die_to_type[src_die];
if (src_child_type)
{
if (log)
- log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset());
+ log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x",
+ static_cast<void*>(src_child_type),
+ src_child_type->GetID(),
+ src_die->GetOffset(), dst_die->GetOffset());
m_die_to_type[dst_die] = src_child_type;
}
else
@@ -5662,11 +5706,11 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
if (log)
log->Printf ("warning: need to create artificial method for 0x%8.8x for method '%s'", dst_die->GetOffset(), dst_name_artificial);
- failures.push_back(dst_die);
+ failures.Append(dst_die);
}
}
- return (failures.size() != 0);
+ return (failures.Size() != 0);
}
TypeSP
@@ -5677,7 +5721,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
if (type_is_new_ptr)
*type_is_new_ptr = false;
-#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE)
+#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE)
static DIEStack g_die_stack;
DIEStack::ScopedPopper scoped_die_logger(g_die_stack);
#endif
@@ -5690,15 +5734,15 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
{
const DWARFDebugInfoEntry *context_die;
clang::DeclContext *context = GetClangDeclContextContainingDIE (dwarf_cu, die, &context_die);
-
+
GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x, decl_ctx = %p (die 0x%8.8x)) %s name = '%s')",
- die->GetOffset(),
- context,
- context_die->GetOffset(),
- DW_TAG_value_to_name(die->Tag()),
- die->GetName(this, dwarf_cu));
-
-#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE)
+ die->GetOffset(),
+ static_cast<void*>(context),
+ context_die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, dwarf_cu));
+
+#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE)
scoped_die_logger.Push (dwarf_cu, die);
g_die_stack.LogDIEs(log, this);
#endif
@@ -5712,7 +5756,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
// GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDwarf::%s %s", __FUNCTION__, s.GetData());
//
// }
-
+
Type *type_ptr = m_die_to_type.lookup (die);
TypeList* type_list = GetTypeList();
if (type_ptr == NULL)
@@ -5733,7 +5777,8 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID;
ClangASTType clang_type;
-
+ DWARFFormValue form_value;
+
dw_attr_t attr;
switch (tag)
@@ -5761,7 +5806,6 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
for (i=0; i<num_attributes; ++i)
{
attr = attributes.AttributeAtIndex(i);
- DWARFFormValue form_value;
if (attributes.ExtractFormValueAtIndex(this, i, form_value))
{
switch (attr)
@@ -5770,7 +5814,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
case DW_AT_name:
-
+
type_name_cstr = form_value.AsCString(&get_debug_str_data());
// Work around a bug in llvm-gcc where they give a name to a reference type which doesn't
// include the "&"...
@@ -5829,7 +5873,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
if (!clang_type && (encoding_data_type == Type::eEncodingIsPointerUID || encoding_data_type == Type::eEncodingIsTypedefUID) && sc.comp_unit != NULL)
{
bool translation_unit_is_objc = (sc.comp_unit->GetLanguage() == eLanguageTypeObjC || sc.comp_unit->GetLanguage() == eLanguageTypeObjC_plus_plus);
-
+
if (translation_unit_is_objc)
{
if (type_name_cstr != NULL)
@@ -5837,7 +5881,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
static ConstString g_objc_type_name_id("id");
static ConstString g_objc_type_name_Class("Class");
static ConstString g_objc_type_name_selector("SEL");
-
+
if (type_name_const_str == g_objc_type_name_id)
{
if (log)
@@ -5879,11 +5923,11 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
else if (encoding_data_type == Type::eEncodingIsPointerUID && encoding_uid != LLDB_INVALID_UID)
{
// Clang sometimes erroneously emits id as objc_object*. In that case we fix up the type to "id".
-
+
DWARFDebugInfoEntry* encoding_die = dwarf_cu->GetDIEPtr(encoding_uid);
-
+
if (encoding_die && encoding_die->Tag() == DW_TAG_structure_type)
- {
+ {
if (const char *struct_name = encoding_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_name, NULL))
{
if (!strcmp(struct_name, "objc_object"))
@@ -5903,7 +5947,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
}
}
}
-
+
type_sp.reset( new Type (MakeUserID(die->GetOffset()),
this,
type_name_const_str,
@@ -5914,7 +5958,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
&decl,
clang_type,
resolve_state));
-
+
m_die_to_type[die] = type_sp.get();
// Type* encoding_type = GetUniquedTypeForDIEOffset(encoding_uid, type_sp, NULL, 0, 0, false);
@@ -5946,7 +5990,6 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
for (i=0; i<num_attributes; ++i)
{
attr = attributes.AttributeAtIndex(i);
- DWARFFormValue form_value;
if (attributes.ExtractFormValueAtIndex(this, i, form_value))
{
switch (attr)
@@ -5996,7 +6039,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
case DW_AT_APPLE_objc_complete_type:
is_complete_objc_class = form_value.Signed();
break;
-
+
case DW_AT_allocated:
case DW_AT_associated:
case DW_AT_data_location:
@@ -6010,8 +6053,11 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
}
}
}
-
- UniqueDWARFASTType unique_ast_entry;
+
+ // UniqueDWARFASTType is large, so don't create a local variables on the
+ // stack, put it on the heap. This function is often called recursively
+ // and clang isn't good and sharing the stack space for variables in different blocks.
+ std::unique_ptr<UniqueDWARFASTType> unique_ast_entry_ap(new UniqueDWARFASTType());
// Only try and unique the type if it has a name.
if (type_name_const_str &&
@@ -6021,21 +6067,21 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
die,
decl,
byte_size_valid ? byte_size : -1,
- unique_ast_entry))
+ *unique_ast_entry_ap))
{
// We have already parsed this type or from another
// compile unit. GCC loves to use the "one definition
// rule" which can result in multiple definitions
// of the same class over and over in each compile
// unit.
- type_sp = unique_ast_entry.m_type_sp;
+ type_sp = unique_ast_entry_ap->m_type_sp;
if (type_sp)
{
m_die_to_type[die] = type_sp.get();
return type_sp;
}
}
-
+
DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr);
int tag_decl_kind = -1;
@@ -6055,7 +6101,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
tag_decl_kind = clang::TTK_Class;
default_accessibility = eAccessPrivate;
}
-
+
if (byte_size_valid && byte_size == 0 && type_name_cstr &&
die->HasChildren() == false &&
sc.comp_unit->GetLanguage() == eLanguageTypeObjC)
@@ -6093,20 +6139,20 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
// else...
type_sp = m_debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE (die, type_name_const_str, true);
}
-
+
if (type_sp)
{
if (log)
{
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is an incomplete objc type, complete type is 0x%8.8" PRIx64,
- this,
+ static_cast<void*>(this),
die->GetOffset(),
DW_TAG_value_to_name(tag),
type_name_cstr,
type_sp->GetID());
}
-
+
// We found a real definition for this type elsewhere
// so lets use it and cache the fact that we found
// a complete type for this die
@@ -6115,7 +6161,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
}
}
}
-
+
if (is_forward_declaration)
{
@@ -6128,12 +6174,12 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
{
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a forward declaration, trying to find complete type",
- this,
+ static_cast<void*>(this),
die->GetOffset(),
DW_TAG_value_to_name(tag),
type_name_cstr);
}
-
+
DWARFDeclContext die_decl_ctx;
die->GetDWARFDeclContext(this, dwarf_cu, die_decl_ctx);
@@ -6154,7 +6200,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
{
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a forward declaration, complete type is 0x%8.8" PRIx64,
- this,
+ static_cast<void*>(this),
die->GetOffset(),
DW_TAG_value_to_name(tag),
type_name_cstr,
@@ -6174,12 +6220,12 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
if (!clang_type)
{
const DWARFDebugInfoEntry *decl_ctx_die;
-
+
clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, &decl_ctx_die);
if (accessibility == eAccessNone && decl_ctx)
{
// Check the decl context that contains this class/struct/union.
- // If it is a class we must give it an accessability.
+ // If it is a class we must give it an accessibility.
const clang::Decl::Kind containing_decl_kind = decl_ctx->getDeclKind();
if (DeclKindIsCXXClass (containing_decl_kind))
accessibility = default_accessibility;
@@ -6199,14 +6245,14 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
type_name_cstr,
tag_decl_kind,
template_param_infos);
-
+
clang::ClassTemplateSpecializationDecl *class_specialization_decl = ast.CreateClassTemplateSpecializationDecl (decl_ctx,
class_template_decl,
tag_decl_kind,
template_param_infos);
clang_type = ast.CreateClassTemplateSpecializationType (class_specialization_decl);
clang_type_was_created = true;
-
+
GetClangASTContext().SetMetadata (class_template_decl, metadata);
GetClangASTContext().SetMetadata (class_specialization_decl, metadata);
}
@@ -6238,22 +6284,22 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
&decl,
clang_type,
Type::eResolveStateForward));
-
+
type_sp->SetIsCompleteObjCClass(is_complete_objc_class);
// Add our type to the unique type map so we don't
// end up creating many copies of the same type over
// and over in the ASTContext for our module
- unique_ast_entry.m_type_sp = type_sp;
- unique_ast_entry.m_symfile = this;
- unique_ast_entry.m_cu = dwarf_cu;
- unique_ast_entry.m_die = die;
- unique_ast_entry.m_declaration = decl;
- unique_ast_entry.m_byte_size = byte_size;
+ unique_ast_entry_ap->m_type_sp = type_sp;
+ unique_ast_entry_ap->m_symfile = this;
+ unique_ast_entry_ap->m_cu = dwarf_cu;
+ unique_ast_entry_ap->m_die = die;
+ unique_ast_entry_ap->m_declaration = decl;
+ unique_ast_entry_ap->m_byte_size = byte_size;
GetUniqueDWARFASTTypeMap().Insert (type_name_const_str,
- unique_ast_entry);
-
+ *unique_ast_entry_ap);
+
if (is_forward_declaration && die->HasChildren())
{
// Check to see if the DIE actually has a definition, some version of GCC will
@@ -6294,32 +6340,25 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
// No children for this struct/union/class, lets finish it
clang_type.StartTagDeclarationDefinition ();
clang_type.CompleteTagDeclarationDefinition ();
-
+
if (tag == DW_TAG_structure_type) // this only applies in C
{
clang::RecordDecl *record_decl = clang_type.GetAsRecordDecl();
-
+
if (record_decl)
- {
- LayoutInfo layout_info;
-
- layout_info.alignment = 0;
- layout_info.bit_size = 0;
-
- m_record_decl_to_layout_map.insert(std::make_pair(record_decl, layout_info));
- }
+ m_record_decl_to_layout_map.insert(std::make_pair(record_decl, LayoutInfo()));
}
}
else if (clang_type_was_created)
{
// Start the definition if the class is not objective C since
// the underlying decls respond to isCompleteDefinition(). Objective
- // C decls dont' respond to isCompleteDefinition() so we can't
- // start the declaration definition right away. For C++ classs/union/structs
+ // C decls don't respond to isCompleteDefinition() so we can't
+ // start the declaration definition right away. For C++ class/union/structs
// we want to start the definition in case the class is needed as the
// declaration context for a contained class or type without the need
// to complete that type..
-
+
if (class_language != eLanguageTypeObjC &&
class_language != eLanguageTypeObjC_plus_plus)
clang_type.StartTagDeclarationDefinition ();
@@ -6334,7 +6373,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
clang_type.SetHasExternalStorage (true);
}
}
-
+
}
break;
@@ -6353,7 +6392,6 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
for (i=0; i<num_attributes; ++i)
{
attr = attributes.AttributeAtIndex(i);
- DWARFFormValue form_value;
if (attributes.ExtractFormValueAtIndex(this, i, form_value))
{
switch (attr)
@@ -6397,12 +6435,12 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
if (enumerator_type)
enumerator_clang_type = enumerator_type->GetClangFullType();
}
-
+
if (!enumerator_clang_type)
enumerator_clang_type = ast.GetBuiltinTypeForDWARFEncodingAndBitSize (NULL,
DW_ATE_signed,
byte_size * 8);
-
+
clang_type = ast.CreateEnumerationType (type_name_cstr,
GetClangDeclContextContainingDIE (dwarf_cu, die, NULL),
decl,
@@ -6414,7 +6452,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
}
LinkDeclContextToDIE(clang_type.GetDeclContextForType(), die);
-
+
type_sp.reset( new Type (MakeUserID(die->GetOffset()),
this,
type_name_const_str,
@@ -6469,7 +6507,6 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
for (i=0; i<num_attributes; ++i)
{
attr = attributes.AttributeAtIndex(i);
- DWARFFormValue form_value;
if (attributes.ExtractFormValueAtIndex(this, i, form_value))
{
switch (attr)
@@ -6491,7 +6528,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
case DW_AT_virtuality: is_virtual = form_value.Boolean(); break;
case DW_AT_explicit: is_explicit = form_value.Boolean(); break;
case DW_AT_artificial: is_artificial = form_value.Boolean(); break;
-
+
case DW_AT_external:
if (form_value.Unsigned())
@@ -6554,12 +6591,12 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
object_pointer_name.assign(s.GetData());
}
}
-
+
DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr);
ClangASTType return_clang_type;
Type *func_type = NULL;
-
+
if (type_die_offset != DW_INVALID_OFFSET)
func_type = ResolveTypeUID(type_die_offset);
@@ -6573,18 +6610,17 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
std::vector<clang::ParmVarDecl*> function_param_decls;
// Parse the function children for the parameters
-
+
const DWARFDebugInfoEntry *decl_ctx_die = NULL;
clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, &decl_ctx_die);
const clang::Decl::Kind containing_decl_kind = containing_decl_ctx->getDeclKind();
const bool is_cxx_method = DeclKindIsCXXClass (containing_decl_kind);
// Start off static. This will be set to false in ParseChildParameters(...)
- // if we find a "this" paramters as the first parameter
+ // if we find a "this" parameters as the first parameter
if (is_cxx_method)
is_static = true;
- ClangASTContext::TemplateParameterInfos template_param_infos;
-
+
if (die->HasChildren())
{
bool skip_artificial = true;
@@ -6598,8 +6634,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
type_list,
function_param_types,
function_param_decls,
- type_quals,
- template_param_infos);
+ type_quals);
}
// clang_type will get the function prototype clang type after this call
@@ -6608,9 +6643,9 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
function_param_types.size(),
is_variadic,
type_quals);
-
+
bool ignore_containing_context = false;
-
+
if (type_name_cstr)
{
bool type_handled = false;
@@ -6619,12 +6654,10 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
ObjCLanguageRuntime::MethodName objc_method (type_name_cstr, true);
if (objc_method.IsValid(true))
{
- SymbolContext empty_sc;
ClangASTType class_opaque_type;
ConstString class_name(objc_method.GetClassName());
if (class_name)
{
- TypeList types;
TypeSP complete_objc_class_type_sp (FindCompleteObjCDefinitionTypeForDIE (NULL, class_name, false));
if (complete_objc_class_type_sp)
@@ -6677,7 +6710,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
SymbolFileDWARF *class_symfile = NULL;
DWARFCompileUnitSP class_type_cu_sp;
const DWARFDebugInfoEntry *class_type_die = NULL;
-
+
SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
if (debug_map_symfile)
{
@@ -6691,8 +6724,8 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
}
if (class_type_die)
{
- llvm::SmallVector<const DWARFDebugInfoEntry *, 0> failures;
-
+ DWARFDIECollection failures;
+
CopyUniqueClassMethodTypes (class_symfile,
class_type,
class_type_cu_sp.get(),
@@ -6700,12 +6733,12 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
dwarf_cu,
decl_ctx_die,
failures);
-
+
// FIXME do something with these failures that's smarter than
// just dropping them on the ground. Unfortunately classes don't
// like having stuff added to them after their definitions are
// complete...
-
+
type_ptr = m_die_to_type[die];
if (type_ptr && type_ptr != DIE_IS_BEING_PARSED)
{
@@ -6714,7 +6747,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
}
}
}
-
+
if (specification_die_offset != DW_INVALID_OFFSET)
{
// We have a specification which we are going to base our function
@@ -6773,7 +6806,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
// in the DWARF for C++ methods... Default to public for now...
if (accessibility == eAccessNone)
accessibility = eAccessPublic;
-
+
if (!is_static && !die->HasChildren())
{
// We have a C++ member function with no children (this pointer!)
@@ -6792,7 +6825,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
m_obj_file->GetFileSpec().GetPath().c_str());
const bool is_attr_used = false;
-
+
cxx_method_decl = class_opaque_type.AddMethodToCXXRecordType (type_name_cstr,
clang_type,
accessibility,
@@ -6802,7 +6835,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
is_explicit,
is_attr_used,
is_artificial);
-
+
type_handled = cxx_method_decl != NULL;
if (type_handled)
@@ -6811,17 +6844,17 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
Host::SetCrashDescription (NULL);
-
+
ClangASTMetadata metadata;
metadata.SetUserID(MakeUserID(die->GetOffset()));
-
+
if (!object_pointer_name.empty())
{
metadata.SetObjectPtrName(object_pointer_name.c_str());
if (log)
log->Printf ("Setting object pointer name: %s on method object %p.\n",
object_pointer_name.c_str(),
- cxx_method_decl);
+ static_cast<void*>(cxx_method_decl));
}
GetClangASTContext().SetMetadata (cxx_method_decl, metadata);
}
@@ -6841,7 +6874,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
// we need to modify the m_die_to_type so it doesn't think we are
// trying to parse this DIE anymore...
m_die_to_type[die] = NULL;
-
+
// Now we get the full type to force our class type to complete itself
// using the clang::ExternalASTSource protocol which will parse all
// base classes and all methods (including the method for this DIE).
@@ -6854,7 +6887,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
type_sp = type_ptr->shared_from_this();
break;
}
-
+
// FIXME This is fixing some even uglier behavior but we really need to
// uniq the methods of each class as well as the class itself.
// <rdar://problem/11240464>
@@ -6865,7 +6898,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
}
}
}
-
+
if (!type_handled)
{
// We just have a function that isn't part of a class
@@ -6893,17 +6926,17 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
ast.SetFunctionParameters (function_decl,
&function_param_decls.front(),
function_param_decls.size());
-
+
ClangASTMetadata metadata;
metadata.SetUserID(MakeUserID(die->GetOffset()));
-
+
if (!object_pointer_name.empty())
{
metadata.SetObjectPtrName(object_pointer_name.c_str());
if (log)
log->Printf ("Setting object pointer name: %s on function object %p.",
object_pointer_name.c_str(),
- function_decl);
+ static_cast<void*>(function_decl));
}
GetClangASTContext().SetMetadata (function_decl, metadata);
}
@@ -6940,7 +6973,6 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
for (i=0; i<num_attributes; ++i)
{
attr = attributes.AttributeAtIndex(i);
- DWARFFormValue form_value;
if (attributes.ExtractFormValueAtIndex(this, i, form_value))
{
switch (attr)
@@ -7022,13 +7054,12 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
dw_offset_t containing_type_die_offset = DW_INVALID_OFFSET;
const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
-
+
if (num_attributes > 0) {
uint32_t i;
for (i=0; i<num_attributes; ++i)
{
attr = attributes.AttributeAtIndex(i);
- DWARFFormValue form_value;
if (attributes.ExtractFormValueAtIndex(this, i, form_value))
{
switch (attr)
@@ -7040,10 +7071,10 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
}
}
}
-
+
Type *pointee_type = ResolveTypeUID(type_die_offset);
Type *class_type = ResolveTypeUID(containing_type_die_offset);
-
+
ClangASTType pointee_clang_type = pointee_type->GetClangForwardType();
ClangASTType class_clang_type = class_type->GetClangLayoutType();
@@ -7062,7 +7093,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu,
clang_type,
Type::eResolveStateForward));
}
-
+
break;
}
default:
@@ -7342,6 +7373,7 @@ SymbolFileDWARF::ParseVariableDIE
bool is_artificial = false;
bool location_is_const_value_data = false;
bool has_explicit_location = false;
+ DWARFFormValue const_value;
//AccessType accessibility = eAccessNone;
for (i=0; i<num_attributes; ++i)
@@ -7380,7 +7412,21 @@ SymbolFileDWARF::ParseVariableDIE
const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
uint32_t data_offset = attributes.DIEOffsetAtIndex(i);
uint32_t data_length = fixed_form_sizes[form_value.Form()];
- location.CopyOpcodeData(module, debug_info_data, data_offset, data_length);
+ if (data_length == 0)
+ {
+ const uint8_t *data_pointer = form_value.BlockData();
+ if (data_pointer)
+ {
+ data_length = form_value.Unsigned();
+ }
+ else if (DWARFFormValue::IsDataForm(form_value.Form()))
+ {
+ // we need to get the byte size of the type later after we create the variable
+ const_value = form_value;
+ }
+ }
+ else
+ location.CopyOpcodeData(module, debug_info_data, data_offset, data_length);
}
else
{
@@ -7455,7 +7501,7 @@ SymbolFileDWARF::ParseVariableDIE
// DWARF doesn't specify if a DW_TAG_variable is a local, global
// or static variable, so we have to do a little digging by
- // looking at the location of a varaible to see if it contains
+ // looking at the location of a variable to see if it contains
// a DW_OP_addr opcode _somewhere_ in the definition. I say
// somewhere because clang likes to combine small global variables
// into the same symbol and have locations like:
@@ -7592,10 +7638,15 @@ SymbolFileDWARF::ParseVariableDIE
if (symbol_context_scope)
{
+ SymbolFileTypeSP type_sp(new SymbolFileType(*this, type_uid));
+
+ if (const_value.Form() && type_sp && type_sp->GetType())
+ location.CopyOpcodeData(const_value.Unsigned(), type_sp->GetType()->GetByteSize(), dwarf_cu->GetAddressByteSize());
+
var_sp.reset (new Variable (MakeUserID(die->GetOffset()),
name,
mangled,
- SymbolFileTypeSP (new SymbolFileType(*this, type_uid)),
+ type_sp,
scope,
symbol_context_scope,
&decl,
@@ -7763,7 +7814,7 @@ SymbolFileDWARF::ParseVariables
if (block == NULL)
{
// This must be a specification or abstract origin with
- // a concrete block couterpart in the current function. We need
+ // a concrete block counterpart in the current function. We need
// to find the concrete block so we can correctly add the
// variable to it
DWARFCompileUnit *concrete_block_die_cu = dwarf_cu;
@@ -8011,12 +8062,11 @@ SymbolFileDWARF::LayoutRecordType (const clang::RecordDecl *record_decl,
if (log)
GetObjectFile()->GetModule()->LogMessage (log,
"SymbolFileDWARF::LayoutRecordType (record_decl = %p, bit_size = %" PRIu64 ", alignment = %" PRIu64 ", field_offsets[%u],base_offsets[%u], vbase_offsets[%u]) success = %i",
- record_decl,
- bit_size,
- alignment,
- (uint32_t)field_offsets.size(),
- (uint32_t)base_offsets.size(),
- (uint32_t)vbase_offsets.size(),
+ static_cast<const void*>(record_decl),
+ bit_size, alignment,
+ static_cast<uint32_t>(field_offsets.size()),
+ static_cast<uint32_t>(base_offsets.size()),
+ static_cast<uint32_t>(vbase_offsets.size()),
success);
return success;
}
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 8dac209361ed..178e5142d94b 100644
--- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -368,9 +368,10 @@ protected:
lldb_private::TypeList* type_list,
std::vector<lldb_private::ClangASTType>& function_args,
std::vector<clang::ParmVarDecl*>& function_param_decls,
- unsigned &type_quals,
- lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos);
-
+ unsigned &type_quals);
+ // lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos); // not currently needed
+
+
size_t ParseChildEnumerators(
const lldb_private::SymbolContext& sc,
lldb_private::ClangASTType &clang_type,
@@ -546,7 +547,7 @@ protected:
const DWARFDebugInfoEntry *src_class_die,
DWARFCompileUnit* dst_cu,
const DWARFDebugInfoEntry *dst_class_die,
- llvm::SmallVectorImpl <const DWARFDebugInfoEntry *> &failures);
+ DWARFDIECollection &failures);
bool
FixupAddress (lldb_private::Address &addr);
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
index 856c42c2c9a6..af16c03a8c07 100644
--- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -55,20 +55,19 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa
Module *oso_module = exe_symfile->GetModuleByCompUnitInfo (this);
if (!oso_module)
return file_range_map;
-
+
ObjectFile *oso_objfile = oso_module->GetObjectFile();
if (!oso_objfile)
return file_range_map;
-
+
Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_MAP));
if (log)
{
ConstString object_name (oso_module->GetObjectName());
log->Printf("%p: SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap ('%s')",
- this,
+ static_cast<void*>(this),
oso_module->GetSpecificationDescription().c_str());
}
-
std::vector<SymbolFileDWARFDebugMap::CompileUnitInfo *> cu_infos;
if (exe_symfile->GetCompUnitInfosForModule(oso_module, cu_infos))
@@ -78,12 +77,12 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa
Symtab *exe_symtab = exe_symfile->GetObjectFile()->GetSymtab();
ModuleSP oso_module_sp (oso_objfile->GetModule());
Symtab *oso_symtab = oso_objfile->GetSymtab();
-
+
///const uint32_t fun_resolve_flags = SymbolContext::Module | eSymbolContextCompUnit | eSymbolContextFunction;
//SectionList *oso_sections = oso_objfile->Sections();
// Now we need to make sections that map from zero based object
- // file addresses to where things eneded up in the main executable.
-
+ // file addresses to where things ended up in the main executable.
+
assert (comp_unit_info->first_symbol_index != UINT32_MAX);
// End index is one past the last valid symbol index
const uint32_t oso_end_idx = comp_unit_info->last_symbol_index + 1;
@@ -96,12 +95,12 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa
{
if (exe_symbol->IsDebug() == false)
continue;
-
+
switch (exe_symbol->GetType())
{
default:
break;
-
+
case eSymbolTypeCode:
{
// For each N_FUN, or function that we run into in the debug map
@@ -112,7 +111,7 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa
// before we parse any dwarf info so that when it goes get parsed
// all section/offset addresses that get registered will resolve
// correctly to the new addresses in the main executable.
-
+
// First we find the original symbol in the .o file's symbol table
Symbol *oso_fun_symbol = oso_symtab->FindFirstSymbolWithNameAndType (exe_symbol->GetMangled().GetName(Mangled::ePreferMangled),
eSymbolTypeCode,
@@ -125,11 +124,11 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa
exe_symbol->GetAddress().GetFileAddress(),
oso_fun_symbol->GetAddress().GetFileAddress(),
std::min<addr_t>(exe_symbol->GetByteSize(), oso_fun_symbol->GetByteSize()));
-
+
}
}
break;
-
+
case eSymbolTypeData:
{
// For each N_GSYM we remap the address for the global by making
@@ -144,13 +143,12 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa
// fix up these addresses further after all globals have been
// parsed to span the gaps, or we can find the global variable
// sizes from the DWARF info as we are parsing.
-
+
// Next we find the non-stab entry that corresponds to the N_GSYM in the .o file
Symbol *oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType (exe_symbol->GetMangled().GetName(Mangled::ePreferMangled),
eSymbolTypeData,
Symtab::eDebugNo,
Symtab::eVisibilityAny);
-
if (exe_symbol && oso_gsym_symbol &&
exe_symbol->ValueIsAddress() &&
oso_gsym_symbol->ValueIsAddress())
@@ -166,7 +164,7 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa
}
}
}
-
+
exe_symfile->FinalizeOSOFileRanges (this);
// We don't need the symbols anymore for the .o files
oso_objfile->ClearSymtab();
@@ -216,7 +214,7 @@ public:
SymbolVendor* symbol_vendor = Module::GetSymbolVendor(can_create, feedback_strm);
if (symbol_vendor)
{
- // Set a a pointer to this class to set our OSO DWARF file know
+ // Set a pointer to this class to set our OSO DWARF file know
// that the DWARF is being used along with a debug map and that
// it will have the remapped sections that we do below.
SymbolFileDWARF *oso_symfile = SymbolFileDWARFDebugMap::GetSymbolFileAsSymbolFileDWARF(symbol_vendor->GetSymbolFile());
@@ -308,7 +306,7 @@ void
SymbolFileDWARFDebugMap::InitializeObject()
{
// Install our external AST source callbacks so we can complete Clang types.
- llvm::OwningPtr<clang::ExternalASTSource> ast_source_ap (
+ llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source_ap (
new ClangExternalASTSourceCallbacks (SymbolFileDWARFDebugMap::CompleteTagDecl,
SymbolFileDWARFDebugMap::CompleteObjCInterfaceDecl,
NULL,
@@ -341,6 +339,7 @@ SymbolFileDWARFDebugMap::InitOSO()
case ObjectFile::eTypeObjectFile:
case ObjectFile::eTypeStubLibrary:
case ObjectFile::eTypeUnknown:
+ case ObjectFile::eTypeJIT:
return;
case ObjectFile::eTypeExecutable:
@@ -505,10 +504,16 @@ SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo (CompileUnitInfo *comp_unit_inf
// use the debug map, to add new sections to each .o file and
// even though a .o file might not have changed, the sections
// that get added to the .o file can change.
+ ArchSpec oso_arch;
+ // Only adopt the architecture from the module (not the vendor or OS)
+ // since .o files for "i386-apple-ios" will historically show up as "i386-apple-macosx"
+ // due to the lack of a LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS
+ // load command...
+ oso_arch.SetTriple(m_obj_file->GetModule()->GetArchitecture().GetTriple().getArchName().str().c_str());
comp_unit_info->oso_sp->module_sp.reset (new DebugMapModule (obj_file->GetModule(),
GetCompUnitInfoIndex(comp_unit_info),
oso_file,
- m_obj_file->GetModule()->GetArchitecture(),
+ oso_arch,
oso_object ? &oso_object : NULL,
0,
oso_object ? &comp_unit_info->oso_mod_time : NULL));
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
index 06330b98dc19..1493292d4b9b 100644
--- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -393,7 +393,7 @@ protected:
LinkOSOFileAddress (SymbolFileDWARF *oso_symfile, lldb::addr_t oso_file_addr);
//------------------------------------------------------------------
- /// Given a line table full of lines with "file adresses" that are
+ /// Given a line table full of lines with "file addresses" that are
/// for a .o file represented by \a oso_symfile, link a new line table
/// and return it.
///
@@ -405,7 +405,7 @@ protected:
///
/// @return
/// Returns a valid line table full of linked addresses, or NULL
- /// if none of the line table adresses exist in the main
+ /// if none of the line table addresses exist in the main
/// executable.
//------------------------------------------------------------------
lldb_private::LineTable *
diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
index 9beba517ec83..8e85d4825281 100644
--- a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
+++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
@@ -145,7 +145,7 @@ SymbolFileSymtab::GetNumCompileUnits()
if (m_source_indexes.empty())
return 0;
- // If we have any source file symbols we will logically orgnize the object symbols
+ // If we have any source file symbols we will logically organize the object symbols
// using these.
return m_source_indexes.size();
}
@@ -366,20 +366,6 @@ SymbolFileSymtab::FindFunctions(const RegularExpression& regex, bool include_inl
return 0;
}
-static int CountMethodArgs(const char *method_signature)
-{
- int num_args = 0;
-
- for (const char *colon_pos = strchr(method_signature, ':');
- colon_pos != NULL;
- colon_pos = strchr(colon_pos + 1, ':'))
- {
- num_args++;
- }
-
- return num_args;
-}
-
uint32_t
SymbolFileSymtab::FindTypes (const lldb_private::SymbolContext& sc,
const lldb_private::ConstString &name,
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
index 8ddc1cd2ee84..b8d56d3909e9 100644
--- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
+++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -42,7 +42,7 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
m_inst_emulator_ap.get())
{
- // The the instruction emulation subclass setup the unwind plan for the
+ // The instruction emulation subclass setup the unwind plan for the
// first instruction.
m_inst_emulator_ap->CreateFunctionEntryUnwind (unwind_plan);
@@ -83,7 +83,7 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
// Initialize the CFA with a known value. In the 32 bit case
// it will be 0x80000000, and in the 64 bit case 0x8000000000000000.
- // We use the address byte size to be safe for any future addresss sizes
+ // We use the address byte size to be safe for any future address sizes
m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
RegisterValue cfa_reg_value;
cfa_reg_value.SetUInt (m_initial_sp, m_cfa_reg_info.byte_size);
@@ -182,7 +182,7 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
// While parsing the instructions of this function, if we've ever
// seen the return address register (aka lr on arm) in a non-IsSame() state,
- // it has been saved on the stack. If it's evern back to IsSame(), we've
+ // it has been saved on the stack. If it's ever back to IsSame(), we've
// executed an epilogue.
if (ra_reg_num != LLDB_INVALID_REGNUM
&& m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
@@ -285,6 +285,14 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
}
bool
+UnwindAssemblyInstEmulation::AugmentUnwindPlanFromCallSite (AddressRange& func,
+ Thread& thread,
+ UnwindPlan& unwind_plan)
+{
+ return false;
+}
+
+bool
UnwindAssemblyInstEmulation::GetFastUnwindPlan (AddressRange& func,
Thread& thread,
UnwindPlan &unwind_plan)
@@ -358,7 +366,8 @@ UnwindAssemblyInstEmulation::GetPluginDescriptionStatic()
uint64_t
UnwindAssemblyInstEmulation::MakeRegisterKindValuePair (const RegisterInfo &reg_info)
{
- uint32_t reg_kind, reg_num;
+ lldb::RegisterKind reg_kind;
+ uint32_t reg_num;
if (EmulateInstruction::GetBestRegisterKindAndNumber (&reg_info, reg_kind, reg_num))
return (uint64_t)reg_kind << 24 | reg_num;
return 0ull;
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
index 6a02f0a55104..758c3ce2e28b 100644
--- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
+++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
@@ -31,6 +31,11 @@ public:
lldb_private::UnwindPlan& unwind_plan);
virtual bool
+ AugmentUnwindPlanFromCallSite (lldb_private::AddressRange& func,
+ lldb_private::Thread& thread,
+ lldb_private::UnwindPlan& unwind_plan);
+
+ virtual bool
GetFastUnwindPlan (lldb_private::AddressRange& func,
lldb_private::Thread& thread,
lldb_private::UnwindPlan &unwind_plan);
diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
index 1768798f71d4..32a21d2b8bb8 100644
--- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
+++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
@@ -27,12 +27,14 @@
using namespace lldb;
using namespace lldb_private;
-enum CPU {
+enum CPU
+{
k_i386,
k_x86_64
};
-enum i386_register_numbers {
+enum i386_register_numbers
+{
k_machine_eax = 0,
k_machine_ecx = 1,
k_machine_edx = 2,
@@ -44,7 +46,8 @@ enum i386_register_numbers {
k_machine_eip = 8
};
-enum x86_64_register_numbers {
+enum x86_64_register_numbers
+{
k_machine_rax = 0,
k_machine_rcx = 1,
k_machine_rdx = 2,
@@ -64,13 +67,15 @@ enum x86_64_register_numbers {
k_machine_rip = 16
};
-struct regmap_ent {
+struct regmap_ent
+{
const char *name;
int machine_regno;
int lldb_regno;
};
-static struct regmap_ent i386_register_map[] = {
+static struct regmap_ent i386_register_map[] =
+{
{"eax", k_machine_eax, -1},
{"ecx", k_machine_ecx, -1},
{"edx", k_machine_edx, -1},
@@ -82,11 +87,12 @@ static struct regmap_ent i386_register_map[] = {
{"eip", k_machine_eip, -1}
};
-const int size_of_i386_register_map = sizeof (i386_register_map) / sizeof (struct regmap_ent);
+const int size_of_i386_register_map = llvm::array_lengthof (i386_register_map);
static int i386_register_map_initialized = 0;
-static struct regmap_ent x86_64_register_map[] = {
+static struct regmap_ent x86_64_register_map[] =
+{
{"rax", k_machine_rax, -1},
{"rcx", k_machine_rcx, -1},
{"rdx", k_machine_rdx, -1},
@@ -106,7 +112,7 @@ static struct regmap_ent x86_64_register_map[] = {
{"rip", k_machine_rip, -1}
};
-const int size_of_x86_64_register_map = sizeof (x86_64_register_map) / sizeof (struct regmap_ent);
+const int size_of_x86_64_register_map = llvm::array_lengthof (x86_64_register_map);
static int x86_64_register_map_initialized = 0;
@@ -114,7 +120,8 @@ static int x86_64_register_map_initialized = 0;
// AssemblyParse_x86 local-file class definition & implementation functions
//-----------------------------------------------------------------------------------------------
-class AssemblyParse_x86 {
+class AssemblyParse_x86
+{
public:
AssemblyParse_x86 (const ExecutionContext &exe_ctx, int cpu, ArchSpec &arch, AddressRange func);
@@ -123,6 +130,8 @@ public:
bool get_non_call_site_unwind_plan (UnwindPlan &unwind_plan);
+ bool augment_unwind_plan_from_call_site (AddressRange& func, UnwindPlan &unwind_plan);
+
bool get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan);
bool find_first_non_prologue_insn (Address &address);
@@ -135,9 +144,14 @@ private:
bool push_0_pattern_p ();
bool mov_rsp_rbp_pattern_p ();
bool sub_rsp_pattern_p (int& amount);
+ bool add_rsp_pattern_p (int& amount);
bool push_reg_p (int& regno);
+ bool pop_reg_p (int& regno);
+ bool push_imm_pattern_p ();
bool mov_reg_to_local_stack_frame_p (int& regno, int& fp_offset);
bool ret_pattern_p ();
+ bool pop_rbp_pattern_p ();
+ bool call_next_insn_pattern_p();
uint32_t extract_4 (uint8_t *b);
bool machine_regno_to_lldb_regno (int machine_regno, uint32_t& lldb_regno);
bool instruction_length (Address addr, int &length);
@@ -149,13 +163,13 @@ private:
Address m_cur_insn;
uint8_t m_cur_insn_bytes[kMaxInstructionByteSize];
- int m_machine_ip_regnum;
- int m_machine_sp_regnum;
- int m_machine_fp_regnum;
+ uint32_t m_machine_ip_regnum;
+ uint32_t m_machine_sp_regnum;
+ uint32_t m_machine_fp_regnum;
- int m_lldb_ip_regnum;
- int m_lldb_sp_regnum;
- int m_lldb_fp_regnum;
+ uint32_t m_lldb_ip_regnum;
+ uint32_t m_lldb_sp_regnum;
+ uint32_t m_lldb_fp_regnum;
int m_wordsize;
int m_cpu;
@@ -166,16 +180,16 @@ private:
};
AssemblyParse_x86::AssemblyParse_x86 (const ExecutionContext &exe_ctx, int cpu, ArchSpec &arch, AddressRange func) :
- m_exe_ctx (exe_ctx),
- m_func_bounds(func),
+ m_exe_ctx (exe_ctx),
+ m_func_bounds(func),
m_cur_insn (),
m_machine_ip_regnum (LLDB_INVALID_REGNUM),
m_machine_sp_regnum (LLDB_INVALID_REGNUM),
m_machine_fp_regnum (LLDB_INVALID_REGNUM),
- m_lldb_ip_regnum (LLDB_INVALID_REGNUM),
+ m_lldb_ip_regnum (LLDB_INVALID_REGNUM),
m_lldb_sp_regnum (LLDB_INVALID_REGNUM),
m_lldb_fp_regnum (LLDB_INVALID_REGNUM),
- m_wordsize (-1),
+ m_wordsize (-1),
m_cpu(cpu),
m_arch(arch)
{
@@ -242,8 +256,8 @@ AssemblyParse_x86::AssemblyParse_x86 (const ExecutionContext &exe_ctx, int cpu,
m_lldb_ip_regnum = lldb_regno;
}
- m_disasm_context = ::LLVMCreateDisasm(m_arch.GetTriple().getTriple().c_str(),
- (void*)this,
+ m_disasm_context = ::LLVMCreateDisasm(m_arch.GetTriple().getTriple().c_str(),
+ (void*)this,
/*TagType=*/1,
NULL,
NULL);
@@ -254,7 +268,7 @@ AssemblyParse_x86::~AssemblyParse_x86 ()
::LLVMDisasmDispose(m_disasm_context);
}
-// This function expects an x86 native register number (i.e. the bits stripped out of the
+// This function expects an x86 native register number (i.e. the bits stripped out of the
// actual instruction), not an lldb register number.
bool
@@ -262,7 +276,8 @@ AssemblyParse_x86::nonvolatile_reg_p (int machine_regno)
{
if (m_cpu == k_i386)
{
- switch (machine_regno) {
+ switch (machine_regno)
+ {
case k_machine_ebx:
case k_machine_ebp: // not actually a nonvolatile but often treated as such by convention
case k_machine_esi:
@@ -275,7 +290,8 @@ AssemblyParse_x86::nonvolatile_reg_p (int machine_regno)
}
if (m_cpu == k_x86_64)
{
- switch (machine_regno) {
+ switch (machine_regno)
+ {
case k_machine_rbx:
case k_machine_rsp:
case k_machine_rbp: // not actually a nonvolatile but often treated as such by convention
@@ -292,7 +308,7 @@ AssemblyParse_x86::nonvolatile_reg_p (int machine_regno)
}
-// Macro to detect if this is a REX mode prefix byte.
+// Macro to detect if this is a REX mode prefix byte.
#define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48)
// The high bit which should be added to the source register number (the "R" bit)
@@ -302,7 +318,8 @@ AssemblyParse_x86::nonvolatile_reg_p (int machine_regno)
#define REX_W_DSTREG(opcode) ((opcode) & 0x1)
// pushq %rbp [0x55]
-bool AssemblyParse_x86::push_rbp_pattern_p () {
+bool AssemblyParse_x86::push_rbp_pattern_p ()
+{
uint8_t *p = m_cur_insn_bytes;
if (*p == 0x55)
return true;
@@ -318,9 +335,20 @@ bool AssemblyParse_x86::push_0_pattern_p ()
return false;
}
+// pushq $0
+// pushl $0
+bool AssemblyParse_x86::push_imm_pattern_p ()
+{
+ uint8_t *p = m_cur_insn_bytes;
+ if (*p == 0x68 || *p == 0x6a)
+ return true;
+ return false;
+}
+
// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5]
// movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5]
-bool AssemblyParse_x86::mov_rsp_rbp_pattern_p () {
+bool AssemblyParse_x86::mov_rsp_rbp_pattern_p ()
+{
uint8_t *p = m_cur_insn_bytes;
if (m_wordsize == 8 && *p == 0x48)
p++;
@@ -331,57 +359,127 @@ bool AssemblyParse_x86::mov_rsp_rbp_pattern_p () {
return false;
}
-// subq $0x20, %rsp
-bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount) {
+// subq $0x20, %rsp
+bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount)
+{
uint8_t *p = m_cur_insn_bytes;
if (m_wordsize == 8 && *p == 0x48)
p++;
// 8-bit immediate operand
- if (*p == 0x83 && *(p + 1) == 0xec) {
+ if (*p == 0x83 && *(p + 1) == 0xec)
+ {
amount = (int8_t) *(p + 2);
return true;
}
// 32-bit immediate operand
- if (*p == 0x81 && *(p + 1) == 0xec) {
+ if (*p == 0x81 && *(p + 1) == 0xec)
+ {
+ amount = (int32_t) extract_4 (p + 2);
+ return true;
+ }
+ return false;
+}
+
+// addq $0x20, %rsp
+bool AssemblyParse_x86::add_rsp_pattern_p (int& amount)
+{
+ uint8_t *p = m_cur_insn_bytes;
+ if (m_wordsize == 8 && *p == 0x48)
+ p++;
+ // 8-bit immediate operand
+ if (*p == 0x83 && *(p + 1) == 0xc4)
+ {
+ amount = (int8_t) *(p + 2);
+ return true;
+ }
+ // 32-bit immediate operand
+ if (*p == 0x81 && *(p + 1) == 0xc4)
+ {
amount = (int32_t) extract_4 (p + 2);
return true;
}
- // Not handled: [0x83 0xc4] for imm8 with neg values
- // [0x81 0xc4] for imm32 with neg values
return false;
}
// pushq %rbx
-// pushl $ebx
-bool AssemblyParse_x86::push_reg_p (int& regno) {
+// pushl %ebx
+bool AssemblyParse_x86::push_reg_p (int& regno)
+{
uint8_t *p = m_cur_insn_bytes;
int regno_prefix_bit = 0;
// If we have a rex prefix byte, check to see if a B bit is set
- if (m_wordsize == 8 && *p == 0x41) {
+ if (m_wordsize == 8 && *p == 0x41)
+ {
regno_prefix_bit = 1 << 3;
p++;
}
- if (*p >= 0x50 && *p <= 0x57) {
+ if (*p >= 0x50 && *p <= 0x57)
+ {
regno = (*p - 0x50) | regno_prefix_bit;
return true;
}
return false;
}
+// popq %rbx
+// popl %ebx
+bool AssemblyParse_x86::pop_reg_p (int& regno)
+{
+ uint8_t *p = m_cur_insn_bytes;
+ int regno_prefix_bit = 0;
+ // If we have a rex prefix byte, check to see if a B bit is set
+ if (m_wordsize == 8 && *p == 0x41)
+ {
+ regno_prefix_bit = 1 << 3;
+ p++;
+ }
+ if (*p >= 0x58 && *p <= 0x5f)
+ {
+ regno = (*p - 0x58) | regno_prefix_bit;
+ return true;
+ }
+ return false;
+}
+
+// popq %rbp [0x5d]
+// popl %ebp [0x5d]
+bool AssemblyParse_x86::pop_rbp_pattern_p ()
+{
+ uint8_t *p = m_cur_insn_bytes;
+ return (*p == 0x5d);
+}
+
+// call $0 [0xe8 0x0 0x0 0x0 0x0]
+bool AssemblyParse_x86::call_next_insn_pattern_p ()
+{
+ uint8_t *p = m_cur_insn_bytes;
+ return (*p == 0xe8) && (*(p+1) == 0x0) && (*(p+2) == 0x0)
+ && (*(p+3) == 0x0) && (*(p+4) == 0x0);
+}
+
// Look for an instruction sequence storing a nonvolatile register
// on to the stack frame.
// movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0]
// movl %eax, -0xc(%ebp) [0x89 0x45 0xf4]
-bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset) {
+
+// The offset value returned in rbp_offset will be positive --
+// but it must be subtraced from the frame base register to get
+// the actual location. The positive value returned for the offset
+// is a convention used elsewhere for CFA offsets et al.
+
+bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset)
+{
uint8_t *p = m_cur_insn_bytes;
int src_reg_prefix_bit = 0;
int target_reg_prefix_bit = 0;
- if (m_wordsize == 8 && REX_W_PREFIX_P (*p)) {
+ if (m_wordsize == 8 && REX_W_PREFIX_P (*p))
+ {
src_reg_prefix_bit = REX_W_SRCREG (*p) << 3;
target_reg_prefix_bit = REX_W_DSTREG (*p) << 3;
- if (target_reg_prefix_bit == 1) {
+ if (target_reg_prefix_bit == 1)
+ {
// rbp/ebp don't need a prefix bit - we know this isn't the
// reg we care about.
return false;
@@ -389,12 +487,13 @@ bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_off
p++;
}
- if (*p == 0x89) {
+ if (*p == 0x89)
+ {
/* Mask off the 3-5 bits which indicate the destination register
if this is a ModR/M byte. */
int opcode_destreg_masked_out = *(p + 1) & (~0x38);
- /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101
+ /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101
and three bits between them, e.g. 01nnn101
We're looking for a destination of ebp-disp8 or ebp-disp32. */
int immsize;
@@ -421,8 +520,8 @@ bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_off
}
// ret [0xc9] or [0xc2 imm8] or [0xca imm8]
-bool
-AssemblyParse_x86::ret_pattern_p ()
+bool
+AssemblyParse_x86::ret_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
if (*p == 0xc9 || *p == 0xc2 || *p == 0xca || *p == 0xc3)
@@ -439,7 +538,7 @@ AssemblyParse_x86::extract_4 (uint8_t *b)
return v;
}
-bool
+bool
AssemblyParse_x86::machine_regno_to_lldb_regno (int machine_regno, uint32_t &lldb_regno)
{
struct regmap_ent *ent;
@@ -479,11 +578,12 @@ AssemblyParse_x86::instruction_length (Address addr, int &length)
const bool prefer_file_cache = true;
Error error;
Target *target = m_exe_ctx.GetTargetPtr();
- if (target->ReadMemory (addr, prefer_file_cache, opcode_data.data(), max_op_byte_size, error) == -1)
+ if (target->ReadMemory (addr, prefer_file_cache, opcode_data.data(),
+ max_op_byte_size, error) == static_cast<size_t>(-1))
{
return false;
}
-
+
char out_string[512];
const addr_t pc = addr.GetFileAddress();
const size_t inst_size = ::LLVMDisasmInstruction (m_disasm_context,
@@ -498,7 +598,7 @@ AssemblyParse_x86::instruction_length (Address addr, int &length)
}
-bool
+bool
AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
{
UnwindPlan::RowSP row(new UnwindPlan::Row);
@@ -552,7 +652,8 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
// An unrecognized/junk instruction
break;
}
- if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes, insn_len, error) == -1)
+ if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
+ insn_len, error) == static_cast<size_t>(-1))
{
// Error reading the instruction out of the file, stop scanning
break;
@@ -631,7 +732,13 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
{
row->SetOffset (current_func_text_offset + insn_len);
UnwindPlan::Row::RegisterLocation regloc;
- regloc.SetAtCFAPlusOffset (-row->GetCFAOffset());
+
+ // stack_offset for 'movq %r15, -80(%rbp)' will be 80.
+ // In the Row, we want to express this as the offset from the CFA. If the frame base
+ // is rbp (like the above instruction), the CFA offset for rbp is probably 16. So we
+ // want to say that the value is stored at the CFA address - 96.
+ regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAOffset()));
+
row->SetRegisterInfo (lldb_regno, regloc);
unwind_plan.AppendRow (row);
// Allocate a new Row, populate it with the existing Row contents.
@@ -679,45 +786,65 @@ loopnext:
m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
current_func_text_offset += insn_len;
}
-
+
// Now look at the byte at the end of the AddressRange for a limited attempt at describing the
// epilogue. We're looking for the sequence
- // [ 0x5d ] mov %rbp, %rsp
+ // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
+ // [ 0xc3 ] ret
+
+ // or
+
+ // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
+ // [ 0xe9 xx xx xx xx ] jmp objc_retainAutoreleaseReturnValue (this is sometimes the final insn in the function)
+
+ // or
+
+ // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
// [ 0xc3 ] ret
// [ 0xe8 xx xx xx xx ] call __stack_chk_fail (this is sometimes the final insn in the function)
// We want to add a Row describing how to unwind when we're stopped on the 'ret' instruction where the
// CFA is no longer defined in terms of rbp, but is now defined in terms of rsp like on function entry.
+ // (or the 'jmp' instruction in the second case)
uint64_t ret_insn_offset = LLDB_INVALID_ADDRESS;
Address end_of_fun(m_func_bounds.GetBaseAddress());
end_of_fun.SetOffset (end_of_fun.GetOffset() + m_func_bounds.GetByteSize());
-
+
if (m_func_bounds.GetByteSize() > 7)
{
uint8_t bytebuf[7];
Address last_seven_bytes(end_of_fun);
last_seven_bytes.SetOffset (last_seven_bytes.GetOffset() - 7);
- if (target->ReadMemory (last_seven_bytes, prefer_file_cache, bytebuf, 7, error) != -1)
+ if (target->ReadMemory (last_seven_bytes, prefer_file_cache, bytebuf, 7,
+ error) != static_cast<size_t>(-1))
{
- if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3) // mov, ret
+ if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3) // mov & ret
{
ret_insn_offset = m_func_bounds.GetByteSize() - 1;
}
- else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3 && bytebuf[2] == 0xe8) // mov, ret, call
+ else if (bytebuf[1] == 0x5d && bytebuf[2] == 0xe9) // mov & jmp
+ {
+ // When the pc is sitting on the 'jmp' instruction, we have the same
+ // unwind state as if it was sitting on a 'ret' instruction.
+ ret_insn_offset = m_func_bounds.GetByteSize() - 5;
+ }
+ else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3 && bytebuf[2] == 0xe8) // mov & ret & call
{
ret_insn_offset = m_func_bounds.GetByteSize() - 6;
}
}
- } else if (m_func_bounds.GetByteSize() > 2)
+ }
+ else if (m_func_bounds.GetByteSize() > 2)
{
uint8_t bytebuf[2];
Address last_two_bytes(end_of_fun);
last_two_bytes.SetOffset (last_two_bytes.GetOffset() - 2);
- if (target->ReadMemory (last_two_bytes, prefer_file_cache, bytebuf, 2, error) != -1)
+ if (target->ReadMemory (last_two_bytes, prefer_file_cache, bytebuf, 2,
+ error) != static_cast<size_t>(-1))
{
- if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov, ret
+ if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov & ret
{
ret_insn_offset = m_func_bounds.GetByteSize() - 1;
}
@@ -734,7 +861,7 @@ loopnext:
epi_row->SetOffset (ret_insn_offset);
epi_row->SetCFARegister (m_lldb_sp_regnum);
epi_row->SetCFAOffset (m_wordsize);
-
+
// caller's stack pointer value before the call insn is the CFA address
epi_regloc.SetIsCFAPlusOffset (0);
epi_row->SetRegisterInfo (m_lldb_sp_regnum, epi_regloc);
@@ -745,7 +872,7 @@ loopnext:
unwind_plan.AppendRow (epi_row);
}
-
+
unwind_plan.SetSourceName ("assembly insn profiling");
unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
@@ -753,13 +880,211 @@ loopnext:
return true;
}
-/* The "fast unwind plan" is valid for functions that follow the usual convention of
+bool
+AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, UnwindPlan &unwind_plan)
+{
+ // Is func address valid?
+ Address addr_start = func.GetBaseAddress();
+ if (!addr_start.IsValid())
+ return false;
+
+ // Is original unwind_plan valid?
+ // unwind_plan should have at least one row which is ABI-default (CFA register is sp),
+ // and another row in mid-function.
+ if (unwind_plan.GetRowCount() < 2)
+ return false;
+ UnwindPlan::RowSP first_row = unwind_plan.GetRowAtIndex (0);
+ if (first_row->GetOffset() != 0)
+ return false;
+ uint32_t cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext()
+ ->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(),
+ first_row->GetCFARegister());
+ if (cfa_reg != m_lldb_sp_regnum || first_row->GetCFAOffset() != m_wordsize)
+ return false;
+
+ Target *target = m_exe_ctx.GetTargetPtr();
+ m_cur_insn = func.GetBaseAddress();
+ uint64_t offset = 0;
+ int row_id = 1;
+ bool unwind_plan_updated = false;
+ UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row));
+ while (func.ContainsFileAddress (m_cur_insn))
+ {
+ int insn_len;
+ if (!instruction_length (m_cur_insn, insn_len)
+ || insn_len == 0 || insn_len > kMaxInstructionByteSize)
+ {
+ // An unrecognized/junk instruction.
+ break;
+ }
+ const bool prefer_file_cache = true;
+ Error error;
+ if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
+ insn_len, error) == static_cast<size_t>(-1))
+ {
+ // Error reading the instruction out of the file, stop scanning.
+ break;
+ }
+
+ // Advance offsets.
+ offset += insn_len;
+ m_cur_insn.SetOffset(m_cur_insn.GetOffset() + insn_len);
+
+ // If we already have one row for this instruction, we can continue.
+ while (row_id < unwind_plan.GetRowCount()
+ && unwind_plan.GetRowAtIndex (row_id)->GetOffset() <= offset)
+ row_id++;
+ UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex (row_id - 1);
+ if (original_row->GetOffset() == offset)
+ {
+ *row = *original_row;
+ continue;
+ }
+
+ if (row_id == 0)
+ {
+ // If we are here, compiler didn't generate CFI for prologue.
+ // This won't happen to GCC or clang.
+ // In this case, bail out directly.
+ return false;
+ }
+
+ // Inspect the instruction to check if we need a new row for it.
+ cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext()
+ ->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(),
+ row->GetCFARegister());
+ if (cfa_reg == m_lldb_sp_regnum)
+ {
+ // CFA register is sp.
+
+ // call next instruction
+ // call 0
+ // => pop %ebx
+ if (call_next_insn_pattern_p ())
+ {
+ row->SetOffset (offset);
+ row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
+
+ UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+ unwind_plan.InsertRow (new_row);
+ unwind_plan_updated = true;
+ continue;
+ }
+
+ // push/pop register
+ int regno;
+ if (push_reg_p (regno))
+ {
+ row->SetOffset (offset);
+ row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
+
+ UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+ unwind_plan.InsertRow (new_row);
+ unwind_plan_updated = true;
+ continue;
+ }
+ if (pop_reg_p (regno))
+ {
+ // Technically, this might be a nonvolatile register recover in epilogue.
+ // We should reset RegisterInfo for the register.
+ // But in practice, previous rule for the register is still valid...
+ // So we ignore this case.
+
+ row->SetOffset (offset);
+ row->SetCFAOffset (-m_wordsize + row->GetCFAOffset());
+
+ UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+ unwind_plan.InsertRow (new_row);
+ unwind_plan_updated = true;
+ continue;
+ }
+
+ // push imm
+ if (push_imm_pattern_p ())
+ {
+ row->SetOffset (offset);
+ row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
+ UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+ unwind_plan.InsertRow (new_row);
+ unwind_plan_updated = true;
+ continue;
+ }
+
+ // add/sub %rsp/%esp
+ int amount;
+ if (add_rsp_pattern_p (amount))
+ {
+ row->SetOffset (offset);
+ row->SetCFAOffset (-amount + row->GetCFAOffset());
+
+ UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+ unwind_plan.InsertRow (new_row);
+ unwind_plan_updated = true;
+ continue;
+ }
+ if (sub_rsp_pattern_p (amount))
+ {
+ row->SetOffset (offset);
+ row->SetCFAOffset (amount + row->GetCFAOffset());
+
+ UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+ unwind_plan.InsertRow (new_row);
+ unwind_plan_updated = true;
+ continue;
+ }
+ }
+ else if (cfa_reg == m_lldb_fp_regnum)
+ {
+ // CFA register is fp.
+
+ // The only case we care about is epilogue:
+ // [0x5d] pop %rbp/%ebp
+ // => [0xc3] ret
+ if (pop_rbp_pattern_p ())
+ {
+ if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
+ 1, error) != static_cast<size_t>(-1)
+ && ret_pattern_p ())
+ {
+ row->SetOffset (offset);
+ row->SetCFARegister (first_row->GetCFARegister());
+ row->SetCFAOffset (m_wordsize);
+
+ UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+ unwind_plan.InsertRow (new_row);
+ unwind_plan_updated = true;
+ continue;
+ }
+ }
+ }
+ else
+ {
+ // CFA register is not sp or fp.
+
+ // This must be hand-written assembly.
+ // Just trust eh_frame and assume we have finished.
+ break;
+ }
+ }
+
+ unwind_plan.SetPlanValidAddressRange (func);
+ if (unwind_plan_updated)
+ {
+ std::string unwind_plan_source (unwind_plan.GetSourceName().AsCString());
+ unwind_plan_source += " plus augmentation from assembly parsing";
+ unwind_plan.SetSourceName (unwind_plan_source.c_str());
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ }
+ return true;
+}
+
+/* The "fast unwind plan" is valid for functions that follow the usual convention of
using the frame pointer register (ebp, rbp), i.e. the function prologue looks like
push %rbp [0x55]
mov %rsp,%rbp [0x48 0x89 0xe5] (this is a 2-byte insn seq on i386)
*/
-bool
+bool
AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan)
{
UnwindPlan::RowSP row(new UnwindPlan::Row);
@@ -776,7 +1101,8 @@ AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_
uint8_t bytebuf[4];
Error error;
const bool prefer_file_cache = true;
- if (target->ReadMemory (func.GetBaseAddress(), prefer_file_cache, bytebuf, sizeof (bytebuf), error) == -1)
+ if (target->ReadMemory (func.GetBaseAddress(), prefer_file_cache, bytebuf,
+ sizeof (bytebuf), error) == static_cast<size_t>(-1))
return false;
uint8_t i386_prologue[] = {0x55, 0x89, 0xe5};
@@ -821,7 +1147,7 @@ AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_
newrow = new UnwindPlan::Row;
*newrow = *row.get();
row.reset(newrow);
-
+
// mov %rsp, %rbp has executed
row->SetCFARegister (m_lldb_fp_regnum);
row->SetCFAOffset (2 * m_wordsize);
@@ -839,7 +1165,7 @@ AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_
return true;
}
-bool
+bool
AssemblyParse_x86::find_first_non_prologue_insn (Address &address)
{
m_cur_insn = m_func_bounds.GetBaseAddress ();
@@ -859,7 +1185,8 @@ AssemblyParse_x86::find_first_non_prologue_insn (Address &address)
// An error parsing the instruction, i.e. probably data/garbage - stop scanning
break;
}
- if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes, insn_len, error) == -1)
+ if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
+ insn_len, error) == static_cast<size_t>(-1))
{
// Error reading the instruction out of the file, stop scanning
break;
@@ -886,11 +1213,11 @@ AssemblyParse_x86::find_first_non_prologue_insn (Address &address)
//-----------------------------------------------------------------------------------------------
-// UnwindAssemblyParser_x86 method definitions
+// UnwindAssemblyParser_x86 method definitions
//-----------------------------------------------------------------------------------------------
-UnwindAssembly_x86::UnwindAssembly_x86 (const ArchSpec &arch, int cpu) :
- lldb_private::UnwindAssembly(arch),
+UnwindAssembly_x86::UnwindAssembly_x86 (const ArchSpec &arch, int cpu) :
+ lldb_private::UnwindAssembly(arch),
m_cpu(cpu),
m_arch(arch)
{
@@ -910,6 +1237,14 @@ UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& func, Th
}
bool
+UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& thread, UnwindPlan& unwind_plan)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
+ return asm_parse.augment_unwind_plan_from_call_site (func, unwind_plan);
+}
+
+bool
UnwindAssembly_x86::GetFastUnwindPlan (AddressRange& func, Thread& thread, UnwindPlan &unwind_plan)
{
ExecutionContext exe_ctx (thread.shared_from_this());
diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h
index eebaa7b6c803..8a4fe7c09800 100644
--- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h
+++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h
@@ -27,6 +27,11 @@ public:
lldb_private::UnwindPlan& unwind_plan);
virtual bool
+ AugmentUnwindPlanFromCallSite (lldb_private::AddressRange& func,
+ lldb_private::Thread& thread,
+ lldb_private::UnwindPlan& unwind_plan);
+
+ virtual bool
GetFastUnwindPlan (lldb_private::AddressRange& func,
lldb_private::Thread& thread,
lldb_private::UnwindPlan &unwind_plan);
diff --git a/source/Symbol/Block.cpp b/source/Symbol/Block.cpp
index 4ab86e54bf68..6a5c651cd017 100644
--- a/source/Symbol/Block.cpp
+++ b/source/Symbol/Block.cpp
@@ -24,7 +24,7 @@ using namespace lldb_private;
Block::Block(lldb::user_id_t uid) :
UserID(uid),
- m_parent_scope (NULL),
+ m_parent_scope (nullptr),
m_children (),
m_ranges (),
m_inlineInfoSP (),
@@ -62,7 +62,7 @@ Block::GetDescription(Stream *s, Function *function, lldb::DescriptionLevel leve
}
}
- if (m_inlineInfoSP.get() != NULL)
+ if (m_inlineInfoSP.get() != nullptr)
{
bool show_fullpaths = (level == eDescriptionLevelVerbose);
m_inlineInfoSP->Dump(s, show_fullpaths);
@@ -83,15 +83,15 @@ Block::Dump(Stream *s, addr_t base_addr, int32_t depth, bool show_context) const
}
}
- s->Printf("%p: ", this);
+ s->Printf("%p: ", static_cast<const void*>(this));
s->Indent();
- *s << "Block" << ((const UserID&)*this);
+ *s << "Block" << static_cast<const UserID&>(*this);
const Block* parent_block = GetParent();
if (parent_block)
{
s->Printf(", parent = {0x%8.8" PRIx64 "}", parent_block->GetID());
}
- if (m_inlineInfoSP.get() != NULL)
+ if (m_inlineInfoSP.get() != nullptr)
{
bool show_fullpaths = false;
m_inlineInfoSP->Dump(s, show_fullpaths);
@@ -100,12 +100,12 @@ Block::Dump(Stream *s, addr_t base_addr, int32_t depth, bool show_context) const
if (!m_ranges.IsEmpty())
{
*s << ", ranges =";
-
+
size_t num_ranges = m_ranges.GetSize();
for (size_t i=0; i<num_ranges; ++i)
{
const Range &range = m_ranges.GetEntryRef(i);
- if (parent_block != NULL && parent_block->Contains(range) == false)
+ if (parent_block != nullptr && parent_block->Contains(range) == false)
*s << '!';
else
*s << ' ';
@@ -139,7 +139,7 @@ Block::FindBlockByID (user_id_t block_id)
if (block_id == GetID())
return this;
- Block *matching_block = NULL;
+ Block *matching_block = nullptr;
collection::const_iterator pos, end = m_children.end();
for (pos = m_children.begin(); pos != end; ++pos)
{
@@ -171,7 +171,7 @@ Block::CalculateSymbolContextCompileUnit ()
{
if (m_parent_scope)
return m_parent_scope->CalculateSymbolContextCompileUnit ();
- return NULL;
+ return nullptr;
}
Function *
@@ -179,7 +179,7 @@ Block::CalculateSymbolContextFunction ()
{
if (m_parent_scope)
return m_parent_scope->CalculateSymbolContextFunction ();
- return NULL;
+ return nullptr;
}
Block *
@@ -214,7 +214,7 @@ Block::DumpAddressRanges (Stream *s, lldb::addr_t base_addr)
bool
Block::Contains (addr_t range_offset) const
{
- return m_ranges.FindEntryThatContains(range_offset) != NULL;
+ return m_ranges.FindEntryThatContains(range_offset) != nullptr;
}
bool
@@ -226,7 +226,7 @@ Block::Contains (const Block *block) const
// Walk the parent chain for "block" and see if any if them match this block
const Block *block_parent;
for (block_parent = block->GetParent();
- block_parent != NULL;
+ block_parent != nullptr;
block_parent = block_parent->GetParent())
{
if (this == block_parent)
@@ -238,7 +238,7 @@ Block::Contains (const Block *block) const
bool
Block::Contains (const Range& range) const
{
- return m_ranges.FindEntryThatContains (range) != NULL;
+ return m_ranges.FindEntryThatContains (range) != nullptr;
}
Block *
@@ -246,7 +246,7 @@ Block::GetParent () const
{
if (m_parent_scope)
return m_parent_scope->CalculateSymbolContextBlock();
- return NULL;
+ return nullptr;
}
Block *
@@ -268,7 +268,7 @@ Block::GetInlinedParent ()
else
return parent_block->GetInlinedParent();
}
- return NULL;
+ return nullptr;
}
@@ -472,7 +472,7 @@ Block::GetBlockVariableList (bool can_create)
{
if (m_parsed_block_variables == false)
{
- if (m_variable_list_sp.get() == NULL && can_create)
+ if (m_variable_list_sp.get() == nullptr && can_create)
{
m_parsed_block_variables = true;
SymbolContext sc;
@@ -505,7 +505,7 @@ Block::AppendBlockVariables (bool can_create,
{
Block *child_block = pos->get();
if (stop_if_child_block_is_inlined_function == false ||
- child_block->GetInlinedFunctionInfo() == NULL)
+ child_block->GetInlinedFunctionInfo() == nullptr)
{
num_variables_added += child_block->AppendBlockVariables (can_create,
get_child_block_variables,
@@ -529,7 +529,7 @@ Block::AppendVariables
uint32_t num_variables_added = 0;
VariableListSP variable_list_sp(GetBlockVariableList(can_create));
- bool is_inlined_function = GetInlinedFunctionInfo() != NULL;
+ bool is_inlined_function = GetInlinedFunctionInfo() != nullptr;
if (variable_list_sp.get())
{
num_variables_added = variable_list_sp->GetSize();
@@ -556,17 +556,17 @@ Block::GetClangDeclContext()
CalculateSymbolContext (&sc);
if (!sc.module_sp)
- return NULL;
+ return nullptr;
SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor();
if (!sym_vendor)
- return NULL;
+ return nullptr;
SymbolFile *sym_file = sym_vendor->GetSymbolFile();
if (!sym_file)
- return NULL;
+ return nullptr;
return sym_file->GetClangDeclContextForTypeUID (sc, m_uid);
}
@@ -606,7 +606,7 @@ Block::GetSibling() const
if (parent_block)
return parent_block->GetSiblingForChild (this);
}
- return NULL;
+ return nullptr;
}
// A parent of child blocks can be asked to find a sibling block given
// one of its child blocks
@@ -626,6 +626,6 @@ Block::GetSiblingForChild (const Block *child_block) const
}
}
}
- return NULL;
+ return nullptr;
}
diff --git a/source/Symbol/ClangASTContext.cpp b/source/Symbol/ClangASTContext.cpp
index 4f30ccfc0de5..aae96bfa9a3b 100644
--- a/source/Symbol/ClangASTContext.cpp
+++ b/source/Symbol/ClangASTContext.cpp
@@ -16,7 +16,7 @@
// Other libraries and framework includes
// Clang headers like to use NDEBUG inside of them to enable/disable debug
-// releated features using "#ifndef NDEBUG" preprocessor blocks to do one thing
+// related features using "#ifndef NDEBUG" preprocessor blocks to do one thing
// or another. This is bad because it means that if clang was built in release
// mode, it assumes that you are building in release mode which is not always
// the case. You can end up with functions that are defined as empty in header
@@ -79,6 +79,16 @@ using namespace lldb_private;
using namespace llvm;
using namespace clang;
+typedef llvm::DenseMap<clang::ASTContext *, ClangASTContext*> ClangASTMap;
+
+static ClangASTMap &
+GetASTMap()
+{
+ static ClangASTMap g_map;
+ return g_map;
+}
+
+
clang::AccessSpecifier
ClangASTContext::ConvertAccessTypeToAccessSpecifier (AccessType access)
{
@@ -103,7 +113,7 @@ ParseLangArgs
{
// FIXME: Cleanup per-file based stuff.
- // Set some properties which depend soley on the input kind; it would be nice
+ // Set some properties which depend solely on the input kind; it would be nice
// to move these to the language standard, and have the driver resolve the
// input kind + language standard.
if (IK == IK_Asm) {
@@ -276,9 +286,9 @@ ClangASTContext::ClangASTContext (const char *target_triple) :
m_identifier_table_ap(),
m_selector_table_ap(),
m_builtins_ap(),
- m_callback_tag_decl (NULL),
- m_callback_objc_decl (NULL),
- m_callback_baton (NULL),
+ m_callback_tag_decl (nullptr),
+ m_callback_objc_decl (nullptr),
+ m_callback_baton (nullptr),
m_pointer_byte_size (0)
{
@@ -291,6 +301,11 @@ ClangASTContext::ClangASTContext (const char *target_triple) :
//----------------------------------------------------------------------
ClangASTContext::~ClangASTContext()
{
+ if (m_ast_ap.get())
+ {
+ GetASTMap().erase(m_ast_ap.get());
+ }
+
m_builtins_ap.reset();
m_selector_table_ap.reset();
m_identifier_table_ap.reset();
@@ -342,12 +357,12 @@ ClangASTContext::HasExternalSource ()
{
ASTContext *ast = getASTContext();
if (ast)
- return ast->getExternalSource () != NULL;
+ return ast->getExternalSource () != nullptr;
return false;
}
void
-ClangASTContext::SetExternalSource (llvm::OwningPtr<ExternalASTSource> &ast_source_ap)
+ClangASTContext::SetExternalSource (llvm::IntrusiveRefCntPtr<ExternalASTSource> &ast_source_ap)
{
ASTContext *ast = getASTContext();
if (ast)
@@ -365,7 +380,7 @@ ClangASTContext::RemoveExternalSource ()
if (ast)
{
- llvm::OwningPtr<ExternalASTSource> empty_ast_source_ap;
+ llvm::IntrusiveRefCntPtr<ExternalASTSource> empty_ast_source_ap;
ast->setExternalSource (empty_ast_source_ap);
ast->getTranslationUnitDecl()->setHasExternalLexicalStorage(false);
//ast->getTranslationUnitDecl()->setHasExternalVisibleStorage(false);
@@ -377,15 +392,14 @@ ClangASTContext::RemoveExternalSource ()
ASTContext *
ClangASTContext::getASTContext()
{
- if (m_ast_ap.get() == NULL)
+ if (m_ast_ap.get() == nullptr)
{
m_ast_ap.reset(new ASTContext (*getLanguageOptions(),
*getSourceManager(),
- getTargetInfo(),
*getIdentifierTable(),
*getSelectorTable(),
- *getBuiltinContext(),
- 0));
+ *getBuiltinContext()));
+ m_ast_ap->InitBuiltinTypes(*getTargetInfo());
if ((m_callback_tag_decl || m_callback_objc_decl) && m_callback_baton)
{
@@ -394,14 +408,23 @@ ClangASTContext::getASTContext()
}
m_ast_ap->getDiagnostics().setClient(getDiagnosticConsumer(), false);
+
+ GetASTMap().insert(std::make_pair(m_ast_ap.get(), this));
}
return m_ast_ap.get();
}
+ClangASTContext*
+ClangASTContext::GetASTContext (clang::ASTContext* ast)
+{
+ ClangASTContext *clang_ast = GetASTMap().lookup(ast);
+ return clang_ast;
+}
+
Builtin::Context *
ClangASTContext::getBuiltinContext()
{
- if (m_builtins_ap.get() == NULL)
+ if (m_builtins_ap.get() == nullptr)
m_builtins_ap.reset (new Builtin::Context());
return m_builtins_ap.get();
}
@@ -409,15 +432,15 @@ ClangASTContext::getBuiltinContext()
IdentifierTable *
ClangASTContext::getIdentifierTable()
{
- if (m_identifier_table_ap.get() == NULL)
- m_identifier_table_ap.reset(new IdentifierTable (*ClangASTContext::getLanguageOptions(), NULL));
+ if (m_identifier_table_ap.get() == nullptr)
+ m_identifier_table_ap.reset(new IdentifierTable (*ClangASTContext::getLanguageOptions(), nullptr));
return m_identifier_table_ap.get();
}
LangOptions *
ClangASTContext::getLanguageOptions()
{
- if (m_language_options_ap.get() == NULL)
+ if (m_language_options_ap.get() == nullptr)
{
m_language_options_ap.reset(new LangOptions());
ParseLangArgs(*m_language_options_ap, IK_ObjCXX);
@@ -429,7 +452,7 @@ ClangASTContext::getLanguageOptions()
SelectorTable *
ClangASTContext::getSelectorTable()
{
- if (m_selector_table_ap.get() == NULL)
+ if (m_selector_table_ap.get() == nullptr)
m_selector_table_ap.reset (new SelectorTable());
return m_selector_table_ap.get();
}
@@ -437,7 +460,7 @@ ClangASTContext::getSelectorTable()
clang::FileManager *
ClangASTContext::getFileManager()
{
- if (m_file_manager_ap.get() == NULL)
+ if (m_file_manager_ap.get() == nullptr)
{
clang::FileSystemOptions file_system_options;
m_file_manager_ap.reset(new clang::FileManager(file_system_options));
@@ -448,7 +471,7 @@ ClangASTContext::getFileManager()
clang::SourceManager *
ClangASTContext::getSourceManager()
{
- if (m_source_manager_ap.get() == NULL)
+ if (m_source_manager_ap.get() == nullptr)
m_source_manager_ap.reset(new clang::SourceManager(*getDiagnosticsEngine(), *getFileManager()));
return m_source_manager_ap.get();
}
@@ -456,7 +479,7 @@ ClangASTContext::getSourceManager()
clang::DiagnosticsEngine *
ClangASTContext::getDiagnosticsEngine()
{
- if (m_diagnostics_engine_ap.get() == NULL)
+ if (m_diagnostics_engine_ap.get() == nullptr)
{
llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_id_sp(new DiagnosticIDs());
m_diagnostics_engine_ap.reset(new DiagnosticsEngine(diag_id_sp, new DiagnosticOptions()));
@@ -494,23 +517,21 @@ private:
DiagnosticConsumer *
ClangASTContext::getDiagnosticConsumer()
{
- if (m_diagnostic_consumer_ap.get() == NULL)
+ if (m_diagnostic_consumer_ap.get() == nullptr)
m_diagnostic_consumer_ap.reset(new NullDiagnosticConsumer);
return m_diagnostic_consumer_ap.get();
}
-TargetOptions *
-ClangASTContext::getTargetOptions()
-{
- if (m_target_options_rp.getPtr() == NULL && !m_target_triple.empty())
+std::shared_ptr<TargetOptions> &
+ClangASTContext::getTargetOptions() {
+ if (m_target_options_rp.get() == nullptr && !m_target_triple.empty())
{
- m_target_options_rp.reset ();
- m_target_options_rp = new TargetOptions();
- if (m_target_options_rp.getPtr() != NULL)
+ m_target_options_rp = std::make_shared<TargetOptions>();
+ if (m_target_options_rp.get() != nullptr)
m_target_options_rp->Triple = m_target_triple;
}
- return m_target_options_rp.getPtr();
+ return m_target_options_rp;
}
@@ -518,7 +539,7 @@ TargetInfo *
ClangASTContext::getTargetInfo()
{
// target_triple should be something like "x86_64-apple-macosx"
- if (m_target_info_ap.get() == NULL && !m_target_triple.empty())
+ if (m_target_info_ap.get() == nullptr && !m_target_triple.empty())
m_target_info_ap.reset (TargetInfo::CreateTargetInfo(*getDiagnosticsEngine(), getTargetOptions()));
return m_target_info_ap.get();
}
@@ -650,7 +671,7 @@ ClangASTContext::GetBasicTypeEnumeration (const ConstString &name)
g_type_map.Append(ConstString("__int128_t").GetCString(), eBasicTypeInt128);
g_type_map.Append(ConstString("__uint128_t").GetCString(), eBasicTypeUnsignedInt128);
- // Miscelaneous
+ // Miscellaneous
g_type_map.Append(ConstString("bool").GetCString(), eBasicTypeBool);
g_type_map.Append(ConstString("float").GetCString(), eBasicTypeFloat);
g_type_map.Append(ConstString("double").GetCString(), eBasicTypeDouble);
@@ -696,7 +717,7 @@ ClangASTContext::GetBasicType (ASTContext *ast, lldb::BasicType basic_type)
{
if (ast)
{
- clang_type_t clang_type = NULL;
+ clang_type_t clang_type = nullptr;
switch (basic_type)
{
@@ -811,7 +832,7 @@ ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name
ASTContext *ast = getASTContext();
#define streq(a,b) strcmp(a,b) == 0
- assert (ast != NULL);
+ assert (ast != nullptr);
if (ast)
{
switch (dw_ate)
@@ -1134,9 +1155,9 @@ ClangASTContext::CreateRecordType (DeclContext *decl_ctx,
ClangASTMetadata *metadata)
{
ASTContext *ast = getASTContext();
- assert (ast != NULL);
+ assert (ast != nullptr);
- if (decl_ctx == NULL)
+ if (decl_ctx == nullptr)
decl_ctx = ast->getTranslationUnitDecl();
@@ -1160,7 +1181,7 @@ ClangASTContext::CreateRecordType (DeclContext *decl_ctx,
decl_ctx,
SourceLocation(),
SourceLocation(),
- is_anonymous ? NULL : &ast->Idents.get(name));
+ is_anonymous ? nullptr : &ast->Idents.get(name));
if (is_anonymous)
decl->setAnonymousStructOrUnion(true);
@@ -1194,7 +1215,7 @@ CreateTemplateParameterList (ASTContext *ast,
{
const char *name = template_param_infos.names[i];
- IdentifierInfo *identifier_info = NULL;
+ IdentifierInfo *identifier_info = nullptr;
if (name && name[0])
identifier_info = &ast->Idents.get(name);
if (template_param_infos.args[i].getKind() == TemplateArgument::Integral)
@@ -1208,7 +1229,7 @@ CreateTemplateParameterList (ASTContext *ast,
identifier_info,
template_param_infos.args[i].getIntegralType(),
parameter_pack,
- NULL));
+ nullptr));
}
else
@@ -1277,7 +1298,7 @@ ClangASTContext::CreateFunctionTemplateSpecializationInfo (FunctionDecl *func_de
func_decl->setFunctionTemplateSpecialization (func_tmpl_decl,
&template_args,
- NULL);
+ nullptr);
}
@@ -1290,8 +1311,8 @@ ClangASTContext::CreateClassTemplateDecl (DeclContext *decl_ctx,
{
ASTContext *ast = getASTContext();
- ClassTemplateDecl *class_template_decl = NULL;
- if (decl_ctx == NULL)
+ ClassTemplateDecl *class_template_decl = nullptr;
+ if (decl_ctx == nullptr)
decl_ctx = ast->getTranslationUnitDecl();
IdentifierInfo &identifier_info = ast->Idents.get(class_name);
@@ -1337,7 +1358,7 @@ ClangASTContext::CreateClassTemplateDecl (DeclContext *decl_ctx,
decl_name,
template_param_list,
template_cxx_decl,
- NULL);
+ nullptr);
if (class_template_decl)
{
@@ -1373,7 +1394,7 @@ ClangASTContext::CreateClassTemplateSpecializationDecl (DeclContext *decl_ctx,
class_template_decl,
&template_param_infos.args.front(),
template_param_infos.args.size(),
- NULL);
+ nullptr);
class_template_specialization_decl->setSpecializationKind(TSK_ExplicitSpecialization);
@@ -1392,222 +1413,6 @@ ClangASTContext::CreateClassTemplateSpecializationType (ClassTemplateSpecializat
return ClangASTType();
}
-static bool
-IsOperator (const char *name, OverloadedOperatorKind &op_kind)
-{
- if (name == NULL || name[0] == '\0')
- return false;
-
-#define OPERATOR_PREFIX "operator"
-#define OPERATOR_PREFIX_LENGTH (sizeof (OPERATOR_PREFIX) - 1)
-
- const char *post_op_name = NULL;
-
- bool no_space = true;
-
- if (::strncmp(name, OPERATOR_PREFIX, OPERATOR_PREFIX_LENGTH))
- return false;
-
- post_op_name = name + OPERATOR_PREFIX_LENGTH;
-
- if (post_op_name[0] == ' ')
- {
- post_op_name++;
- no_space = false;
- }
-
-#undef OPERATOR_PREFIX
-#undef OPERATOR_PREFIX_LENGTH
-
- // This is an operator, set the overloaded operator kind to invalid
- // in case this is a conversion operator...
- op_kind = NUM_OVERLOADED_OPERATORS;
-
- switch (post_op_name[0])
- {
- default:
- if (no_space)
- return false;
- break;
- case 'n':
- if (no_space)
- return false;
- if (strcmp (post_op_name, "new") == 0)
- op_kind = OO_New;
- else if (strcmp (post_op_name, "new[]") == 0)
- op_kind = OO_Array_New;
- break;
-
- case 'd':
- if (no_space)
- return false;
- if (strcmp (post_op_name, "delete") == 0)
- op_kind = OO_Delete;
- else if (strcmp (post_op_name, "delete[]") == 0)
- op_kind = OO_Array_Delete;
- break;
-
- case '+':
- if (post_op_name[1] == '\0')
- op_kind = OO_Plus;
- else if (post_op_name[2] == '\0')
- {
- if (post_op_name[1] == '=')
- op_kind = OO_PlusEqual;
- else if (post_op_name[1] == '+')
- op_kind = OO_PlusPlus;
- }
- break;
-
- case '-':
- if (post_op_name[1] == '\0')
- op_kind = OO_Minus;
- else if (post_op_name[2] == '\0')
- {
- switch (post_op_name[1])
- {
- case '=': op_kind = OO_MinusEqual; break;
- case '-': op_kind = OO_MinusMinus; break;
- case '>': op_kind = OO_Arrow; break;
- }
- }
- else if (post_op_name[3] == '\0')
- {
- if (post_op_name[2] == '*')
- op_kind = OO_ArrowStar; break;
- }
- break;
-
- case '*':
- if (post_op_name[1] == '\0')
- op_kind = OO_Star;
- else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
- op_kind = OO_StarEqual;
- break;
-
- case '/':
- if (post_op_name[1] == '\0')
- op_kind = OO_Slash;
- else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
- op_kind = OO_SlashEqual;
- break;
-
- case '%':
- if (post_op_name[1] == '\0')
- op_kind = OO_Percent;
- else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
- op_kind = OO_PercentEqual;
- break;
-
-
- case '^':
- if (post_op_name[1] == '\0')
- op_kind = OO_Caret;
- else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
- op_kind = OO_CaretEqual;
- break;
-
- case '&':
- if (post_op_name[1] == '\0')
- op_kind = OO_Amp;
- else if (post_op_name[2] == '\0')
- {
- switch (post_op_name[1])
- {
- case '=': op_kind = OO_AmpEqual; break;
- case '&': op_kind = OO_AmpAmp; break;
- }
- }
- break;
-
- case '|':
- if (post_op_name[1] == '\0')
- op_kind = OO_Pipe;
- else if (post_op_name[2] == '\0')
- {
- switch (post_op_name[1])
- {
- case '=': op_kind = OO_PipeEqual; break;
- case '|': op_kind = OO_PipePipe; break;
- }
- }
- break;
-
- case '~':
- if (post_op_name[1] == '\0')
- op_kind = OO_Tilde;
- break;
-
- case '!':
- if (post_op_name[1] == '\0')
- op_kind = OO_Exclaim;
- else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
- op_kind = OO_ExclaimEqual;
- break;
-
- case '=':
- if (post_op_name[1] == '\0')
- op_kind = OO_Equal;
- else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
- op_kind = OO_EqualEqual;
- break;
-
- case '<':
- if (post_op_name[1] == '\0')
- op_kind = OO_Less;
- else if (post_op_name[2] == '\0')
- {
- switch (post_op_name[1])
- {
- case '<': op_kind = OO_LessLess; break;
- case '=': op_kind = OO_LessEqual; break;
- }
- }
- else if (post_op_name[3] == '\0')
- {
- if (post_op_name[2] == '=')
- op_kind = OO_LessLessEqual;
- }
- break;
-
- case '>':
- if (post_op_name[1] == '\0')
- op_kind = OO_Greater;
- else if (post_op_name[2] == '\0')
- {
- switch (post_op_name[1])
- {
- case '>': op_kind = OO_GreaterGreater; break;
- case '=': op_kind = OO_GreaterEqual; break;
- }
- }
- else if (post_op_name[1] == '>' &&
- post_op_name[2] == '=' &&
- post_op_name[3] == '\0')
- {
- op_kind = OO_GreaterGreaterEqual;
- }
- break;
-
- case ',':
- if (post_op_name[1] == '\0')
- op_kind = OO_Comma;
- break;
-
- case '(':
- if (post_op_name[1] == ')' && post_op_name[2] == '\0')
- op_kind = OO_Call;
- break;
-
- case '[':
- if (post_op_name[1] == ']' && post_op_name[2] == '\0')
- op_kind = OO_Subscript;
- break;
- }
-
- return true;
-}
-
static inline bool
check_op_param (uint32_t op_kind, bool unary, bool binary, uint32_t num_params)
{
@@ -1615,7 +1420,7 @@ check_op_param (uint32_t op_kind, bool unary, bool binary, uint32_t num_params)
if(op_kind == OO_Call)
return true;
- // The parameter count doens't include "this"
+ // The parameter count doesn't include "this"
if (num_params == 0)
return unary;
if (num_params == 1)
@@ -1686,7 +1491,7 @@ ClangASTContext::FieldIsBitfield
uint32_t& bitfield_bit_size
)
{
- if (ast == NULL || field == NULL)
+ if (ast == nullptr || field == nullptr)
return false;
if (field->isBitField())
@@ -1708,7 +1513,7 @@ ClangASTContext::FieldIsBitfield
bool
ClangASTContext::RecordHasFields (const RecordDecl *record_decl)
{
- if (record_decl == NULL)
+ if (record_decl == nullptr)
return false;
if (!record_decl->field_empty())
@@ -1744,16 +1549,16 @@ ClangASTContext::CreateObjCClass
)
{
ASTContext *ast = getASTContext();
- assert (ast != NULL);
+ assert (ast != nullptr);
assert (name && name[0]);
- if (decl_ctx == NULL)
+ if (decl_ctx == nullptr)
decl_ctx = ast->getTranslationUnitDecl();
ObjCInterfaceDecl *decl = ObjCInterfaceDecl::Create (*ast,
decl_ctx,
SourceLocation(),
&ast->Idents.get(name),
- NULL,
+ nullptr,
SourceLocation(),
/*isForwardDecl,*/
isInternal);
@@ -1804,10 +1609,10 @@ ClangASTContext::GetNumBaseClasses (const CXXRecordDecl *cxx_record_decl, bool o
NamespaceDecl *
ClangASTContext::GetUniqueNamespaceDeclaration (const char *name, DeclContext *decl_ctx)
{
- NamespaceDecl *namespace_decl = NULL;
+ NamespaceDecl *namespace_decl = nullptr;
ASTContext *ast = getASTContext();
TranslationUnitDecl *translation_unit_decl = ast->getTranslationUnitDecl ();
- if (decl_ctx == NULL)
+ if (decl_ctx == nullptr)
decl_ctx = translation_unit_decl;
if (name)
@@ -1828,7 +1633,7 @@ ClangASTContext::GetUniqueNamespaceDeclaration (const char *name, DeclContext *d
SourceLocation(),
SourceLocation(),
&identifier_info,
- NULL);
+ nullptr);
decl_ctx->addDecl (namespace_decl);
}
@@ -1845,8 +1650,8 @@ ClangASTContext::GetUniqueNamespaceDeclaration (const char *name, DeclContext *d
false,
SourceLocation(),
SourceLocation(),
- NULL,
- NULL);
+ nullptr,
+ nullptr);
translation_unit_decl->setAnonymousNamespace (namespace_decl);
translation_unit_decl->addDecl (namespace_decl);
assert (namespace_decl == translation_unit_decl->getAnonymousNamespace());
@@ -1864,8 +1669,8 @@ ClangASTContext::GetUniqueNamespaceDeclaration (const char *name, DeclContext *d
false,
SourceLocation(),
SourceLocation(),
- NULL,
- NULL);
+ nullptr,
+ nullptr);
parent_namespace_decl->setAnonymousNamespace (namespace_decl);
parent_namespace_decl->addDecl (namespace_decl);
assert (namespace_decl == parent_namespace_decl->getAnonymousNamespace());
@@ -1910,9 +1715,9 @@ ClangASTContext::CreateFunctionDeclaration (DeclContext *decl_ctx,
int storage,
bool is_inline)
{
- FunctionDecl *func_decl = NULL;
+ FunctionDecl *func_decl = nullptr;
ASTContext *ast = getASTContext();
- if (decl_ctx == NULL)
+ if (decl_ctx == nullptr)
decl_ctx = ast->getTranslationUnitDecl();
@@ -1927,7 +1732,7 @@ ClangASTContext::CreateFunctionDeclaration (DeclContext *decl_ctx,
SourceLocation(),
DeclarationName (&ast->Idents.get(name)),
function_clang_type.GetQualType(),
- NULL,
+ nullptr,
(FunctionDecl::StorageClass)storage,
is_inline,
hasWrittenPrototype,
@@ -1941,7 +1746,7 @@ ClangASTContext::CreateFunctionDeclaration (DeclContext *decl_ctx,
SourceLocation(),
DeclarationName (),
function_clang_type.GetQualType(),
- NULL,
+ nullptr,
(FunctionDecl::StorageClass)storage,
is_inline,
hasWrittenPrototype,
@@ -1965,7 +1770,7 @@ ClangASTContext::CreateFunctionType (ASTContext *ast,
bool is_variadic,
unsigned type_quals)
{
- assert (ast != NULL);
+ assert (ast != nullptr);
std::vector<QualType> qual_type_args;
for (unsigned i=0; i<num_args; ++i)
qual_type_args.push_back (args[i].GetQualType());
@@ -1973,12 +1778,10 @@ ClangASTContext::CreateFunctionType (ASTContext *ast,
// TODO: Detect calling convention in DWARF?
FunctionProtoType::ExtProtoInfo proto_info;
proto_info.Variadic = is_variadic;
- proto_info.ExceptionSpecType = EST_None;
+ proto_info.ExceptionSpec = EST_None;
proto_info.TypeQuals = type_quals;
proto_info.RefQualifier = RQ_None;
- proto_info.NumExceptions = 0;
- proto_info.Exceptions = NULL;
-
+
return ClangASTType (ast, ast->getFunctionType (result_type.GetQualType(),
qual_type_args,
proto_info).getAsOpaquePtr());
@@ -1988,16 +1791,16 @@ ParmVarDecl *
ClangASTContext::CreateParameterDeclaration (const char *name, const ClangASTType &param_type, int storage)
{
ASTContext *ast = getASTContext();
- assert (ast != NULL);
+ assert (ast != nullptr);
return ParmVarDecl::Create(*ast,
ast->getTranslationUnitDecl(),
SourceLocation(),
SourceLocation(),
- name && name[0] ? &ast->Idents.get(name) : NULL,
+ name && name[0] ? &ast->Idents.get(name) : nullptr,
param_type.GetQualType(),
- NULL,
+ nullptr,
(VarDecl::StorageClass)storage,
- 0);
+ nullptr);
}
void
@@ -2018,7 +1821,7 @@ ClangASTContext::CreateArrayType (const ClangASTType &element_type,
if (element_type.IsValid())
{
ASTContext *ast = getASTContext();
- assert (ast != NULL);
+ assert (ast != nullptr);
if (is_vector)
{
@@ -2071,8 +1874,8 @@ ClangASTContext::CreateEnumerationType
decl_ctx,
SourceLocation(),
SourceLocation(),
- name && name[0] ? &ast->Idents.get(name) : NULL,
- NULL,
+ name && name[0] ? &ast->Idents.get(name) : nullptr,
+ nullptr,
false, // IsScoped
false, // IsScopedUsingClassTag
false); // IsFixed
@@ -2131,6 +1934,63 @@ ClangASTContext::CreateEnumerationType
// return false;
//}
+ClangASTType
+ClangASTContext::GetIntTypeFromBitSize (clang::ASTContext *ast,
+ size_t bit_size, bool is_signed)
+{
+ if (ast)
+ {
+ if (is_signed)
+ {
+ if (bit_size == ast->getTypeSize(ast->SignedCharTy))
+ return ClangASTType(ast, ast->SignedCharTy.getAsOpaquePtr());
+
+ if (bit_size == ast->getTypeSize(ast->ShortTy))
+ return ClangASTType(ast, ast->ShortTy.getAsOpaquePtr());
+
+ if (bit_size == ast->getTypeSize(ast->IntTy))
+ return ClangASTType(ast, ast->IntTy.getAsOpaquePtr());
+
+ if (bit_size == ast->getTypeSize(ast->LongTy))
+ return ClangASTType(ast, ast->LongTy.getAsOpaquePtr());
+
+ if (bit_size == ast->getTypeSize(ast->LongLongTy))
+ return ClangASTType(ast, ast->LongLongTy.getAsOpaquePtr());
+
+ if (bit_size == ast->getTypeSize(ast->Int128Ty))
+ return ClangASTType(ast, ast->Int128Ty.getAsOpaquePtr());
+ }
+ else
+ {
+ if (bit_size == ast->getTypeSize(ast->UnsignedCharTy))
+ return ClangASTType(ast, ast->UnsignedCharTy.getAsOpaquePtr());
+
+ if (bit_size == ast->getTypeSize(ast->UnsignedShortTy))
+ return ClangASTType(ast, ast->UnsignedShortTy.getAsOpaquePtr());
+
+ if (bit_size == ast->getTypeSize(ast->UnsignedIntTy))
+ return ClangASTType(ast, ast->UnsignedIntTy.getAsOpaquePtr());
+
+ if (bit_size == ast->getTypeSize(ast->UnsignedLongTy))
+ return ClangASTType(ast, ast->UnsignedLongTy.getAsOpaquePtr());
+
+ if (bit_size == ast->getTypeSize(ast->UnsignedLongLongTy))
+ return ClangASTType(ast, ast->UnsignedLongLongTy.getAsOpaquePtr());
+
+ if (bit_size == ast->getTypeSize(ast->UnsignedInt128Ty))
+ return ClangASTType(ast, ast->UnsignedInt128Ty.getAsOpaquePtr());
+ }
+ }
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTContext::GetPointerSizedIntType (clang::ASTContext *ast, bool is_signed)
+{
+ if (ast)
+ return GetIntTypeFromBitSize(ast, ast->getTypeSize(ast->VoidPtrTy), is_signed);
+ return ClangASTType();
+}
ClangASTType
ClangASTContext::GetFloatTypeFromBitSize (clang::ASTContext *ast,
@@ -2223,7 +2083,7 @@ ClangASTContext::GetMetadata (clang::ASTContext *ast,
if (external_source && external_source->HasMetadata(object))
return external_source->GetMetadata(object);
else
- return NULL;
+ return nullptr;
}
clang::DeclContext *
diff --git a/source/Symbol/ClangASTImporter.cpp b/source/Symbol/ClangASTImporter.cpp
index afdca97ece27..6579afb2f748 100644
--- a/source/Symbol/ClangASTImporter.cpp
+++ b/source/Symbol/ClangASTImporter.cpp
@@ -106,7 +106,7 @@ ClangASTImporter::CopyDecl (clang::ASTContext *dst_ast,
return result;
}
- return NULL;
+ return nullptr;
}
lldb::clang_type_t
@@ -117,7 +117,7 @@ ClangASTImporter::DeportType (clang::ASTContext *dst_ctx,
MinionSP minion_sp (GetMinion (dst_ctx, src_ctx));
if (!minion_sp)
- return NULL;
+ return nullptr;
std::set<NamedDecl *> decls_to_deport;
std::set<NamedDecl *> decls_already_deported;
@@ -130,7 +130,7 @@ ClangASTImporter::DeportType (clang::ASTContext *dst_ctx,
minion_sp->ExecuteDeportWorkQueues();
if (!result)
- return NULL;
+ return nullptr;
return result;
@@ -142,39 +142,36 @@ ClangASTImporter::DeportDecl (clang::ASTContext *dst_ctx,
clang::Decl *decl)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (log)
log->Printf(" [ClangASTImporter] DeportDecl called on (%sDecl*)%p from (ASTContext*)%p to (ASTContex*)%p",
- decl->getDeclKindName(),
- decl,
- src_ctx,
- dst_ctx);
-
+ decl->getDeclKindName(), static_cast<void*>(decl),
+ static_cast<void*>(src_ctx),
+ static_cast<void*>(dst_ctx));
+
MinionSP minion_sp (GetMinion (dst_ctx, src_ctx));
-
+
if (!minion_sp)
- return NULL;
-
+ return nullptr;
+
std::set<NamedDecl *> decls_to_deport;
std::set<NamedDecl *> decls_already_deported;
-
+
minion_sp->InitDeportWorkQueues(&decls_to_deport,
&decls_already_deported);
-
+
clang::Decl *result = CopyDecl(dst_ctx, src_ctx, decl);
minion_sp->ExecuteDeportWorkQueues();
-
+
if (!result)
- return NULL;
-
+ return nullptr;
+
if (log)
log->Printf(" [ClangASTImporter] DeportDecl deported (%sDecl*)%p to (%sDecl*)%p",
- decl->getDeclKindName(),
- decl,
- result->getDeclKindName(),
- result);
-
+ decl->getDeclKindName(), static_cast<void*>(decl),
+ result->getDeclKindName(), static_cast<void*>(result));
+
return result;
}
@@ -183,11 +180,10 @@ ClangASTImporter::CompleteDecl (clang::Decl *decl)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
- if (log)
+ if (log)
log->Printf(" [ClangASTImporter] CompleteDecl called on (%sDecl*)%p",
- decl->getDeclKindName(),
- decl);
-
+ decl->getDeclKindName(), static_cast<void*>(decl));
+
if (ObjCInterfaceDecl *interface_decl = dyn_cast<ObjCInterfaceDecl>(decl))
{
if (!interface_decl->getDefinition())
@@ -412,9 +408,10 @@ void
ClangASTImporter::ForgetDestination (clang::ASTContext *dst_ast)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (log)
- log->Printf(" [ClangASTImporter] Forgetting destination (ASTContext*)%p", dst_ast);
+ log->Printf(" [ClangASTImporter] Forgetting destination (ASTContext*)%p",
+ static_cast<void*>(dst_ast));
m_metadata_map.erase(dst_ast);
}
@@ -423,17 +420,18 @@ void
ClangASTImporter::ForgetSource (clang::ASTContext *dst_ast, clang::ASTContext *src_ast)
{
ASTContextMetadataSP md = MaybeGetContextMetadata (dst_ast);
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
if (log)
- log->Printf(" [ClangASTImporter] Forgetting source->dest (ASTContext*)%p->(ASTContext*)%p", src_ast, dst_ast);
-
+ log->Printf(" [ClangASTImporter] Forgetting source->dest (ASTContext*)%p->(ASTContext*)%p",
+ static_cast<void*>(src_ast), static_cast<void*>(dst_ast));
+
if (!md)
return;
-
+
md->m_minions.erase(src_ast);
-
+
for (OriginMap::iterator iter = md->m_origins.begin();
iter != md->m_origins.end();
)
@@ -503,8 +501,8 @@ ClangASTImporter::Minion::ExecuteDeportWorkQueues ()
to_context_md->m_origins.erase(decl);
}
- m_decls_to_deport = NULL;
- m_decls_already_deported = NULL;
+ m_decls_to_deport = nullptr;
+ m_decls_already_deported = nullptr;
}
void
@@ -572,64 +570,64 @@ clang::Decl *
ClangASTImporter::Minion::Imported (clang::Decl *from, clang::Decl *to)
{
ClangASTMetrics::RegisterClangImport();
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
-
+
+ lldb::user_id_t user_id = LLDB_INVALID_UID;
+ ClangASTMetadata *metadata = m_master.GetDeclMetadata(from);
+ if (metadata)
+ user_id = metadata->GetUserID();
+
if (log)
{
- lldb::user_id_t user_id;
- ClangASTMetadata *metadata = m_master.GetDeclMetadata(from);
- if (metadata)
- user_id = metadata->GetUserID();
-
if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from))
{
std::string name_string;
llvm::raw_string_ostream name_stream(name_string);
from_named_decl->printName(name_stream);
name_stream.flush();
-
+
log->Printf(" [ClangASTImporter] Imported (%sDecl*)%p, named %s (from (Decl*)%p), metadata 0x%" PRIx64,
- from->getDeclKindName(),
- to,
- name_string.c_str(),
- from,
+ from->getDeclKindName(), static_cast<void*>(to),
+ name_string.c_str(), static_cast<void*>(from),
user_id);
}
else
{
log->Printf(" [ClangASTImporter] Imported (%sDecl*)%p (from (Decl*)%p), metadata 0x%" PRIx64,
- from->getDeclKindName(),
- to,
- from,
- user_id);
+ from->getDeclKindName(), static_cast<void*>(to),
+ static_cast<void*>(from), user_id);
}
}
ASTContextMetadataSP to_context_md = m_master.GetContextMetadata(&to->getASTContext());
ASTContextMetadataSP from_context_md = m_master.MaybeGetContextMetadata(m_source_ctx);
-
+
if (from_context_md)
{
OriginMap &origins = from_context_md->m_origins;
-
+
OriginMap::iterator origin_iter = origins.find(from);
-
+
if (origin_iter != origins.end())
{
- to_context_md->m_origins[to] = origin_iter->second;
-
+ if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() ||
+ user_id != LLDB_INVALID_UID)
+ {
+ to_context_md->m_origins[to] = origin_iter->second;
+ }
+
MinionSP direct_completer = m_master.GetMinion(&to->getASTContext(), origin_iter->second.ctx);
-
+
if (direct_completer.get() != this)
direct_completer->ASTImporter::Imported(origin_iter->second.decl, to);
-
+
if (log)
log->Printf(" [ClangASTImporter] Propagated origin (Decl*)%p/(ASTContext*)%p from (ASTContext*)%p to (ASTContext*)%p",
- origin_iter->second.decl,
- origin_iter->second.ctx,
- &from->getASTContext(),
- &to->getASTContext());
+ static_cast<void*>(origin_iter->second.decl),
+ static_cast<void*>(origin_iter->second.ctx),
+ static_cast<void*>(&from->getASTContext()),
+ static_cast<void*>(&to->getASTContext()));
}
else
{
@@ -638,27 +636,31 @@ ClangASTImporter::Minion::Imported (clang::Decl *from, clang::Decl *to)
if (isa<TagDecl>(to) || isa<ObjCInterfaceDecl>(to))
{
NamedDecl *to_named_decl = dyn_cast<NamedDecl>(to);
-
+
if (!m_decls_already_deported->count(to_named_decl))
m_decls_to_deport->insert(to_named_decl);
}
-
}
- to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from);
+ if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() ||
+ user_id != LLDB_INVALID_UID)
+ {
+ to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from);
+ }
+
if (log)
log->Printf(" [ClangASTImporter] Decl has no origin information in (ASTContext*)%p",
- &from->getASTContext());
+ static_cast<void*>(&from->getASTContext()));
}
-
+
if (clang::NamespaceDecl *to_namespace = dyn_cast<clang::NamespaceDecl>(to))
{
clang::NamespaceDecl *from_namespace = dyn_cast<clang::NamespaceDecl>(from);
-
+
NamespaceMetaMap &namespace_maps = from_context_md->m_namespace_maps;
-
+
NamespaceMetaMap::iterator namespace_map_iter = namespace_maps.find(from_namespace);
-
+
if (namespace_map_iter != namespace_maps.end())
to_context_md->m_namespace_maps[to_namespace] = namespace_map_iter->second;
}
@@ -666,21 +668,21 @@ ClangASTImporter::Minion::Imported (clang::Decl *from, clang::Decl *to)
else
{
to_context_md->m_origins[to] = DeclOrigin (m_source_ctx, from);
-
+
if (log)
log->Printf(" [ClangASTImporter] Sourced origin (Decl*)%p/(ASTContext*)%p into (ASTContext*)%p",
- from,
- m_source_ctx,
- &to->getASTContext());
+ static_cast<void*>(from),
+ static_cast<void*>(m_source_ctx),
+ static_cast<void*>(&to->getASTContext()));
}
-
+
if (TagDecl *from_tag_decl = dyn_cast<TagDecl>(from))
{
TagDecl *to_tag_decl = dyn_cast<TagDecl>(to);
-
+
to_tag_decl->setHasExternalLexicalStorage();
to_tag_decl->setMustBuildLookupTable();
-
+
if (log)
log->Printf(" [ClangASTImporter] To is a TagDecl - attributes %s%s [%s->%s]",
(to_tag_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
@@ -688,32 +690,32 @@ ClangASTImporter::Minion::Imported (clang::Decl *from, clang::Decl *to)
(from_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"),
(to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"));
}
-
+
if (isa<NamespaceDecl>(from))
{
NamespaceDecl *to_namespace_decl = dyn_cast<NamespaceDecl>(to);
-
+
m_master.BuildNamespaceMap(to_namespace_decl);
-
+
to_namespace_decl->setHasExternalVisibleStorage();
}
-
+
if (isa<ObjCInterfaceDecl>(from))
{
ObjCInterfaceDecl *to_interface_decl = dyn_cast<ObjCInterfaceDecl>(to);
-
+
to_interface_decl->setHasExternalLexicalStorage();
to_interface_decl->setHasExternalVisibleStorage();
-
+
/*to_interface_decl->setExternallyCompleted();*/
-
+
if (log)
log->Printf(" [ClangASTImporter] To is an ObjCInterfaceDecl - attributes %s%s%s",
(to_interface_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
(to_interface_decl->hasExternalVisibleStorage() ? " Visible" : ""),
(to_interface_decl->hasDefinition() ? " HasDefinition" : ""));
}
-
+
return clang::ASTImporter::Imported(from, to);
}
@@ -722,12 +724,12 @@ clang::Decl *ClangASTImporter::Minion::GetOriginalDecl (clang::Decl *To)
ASTContextMetadataSP to_context_md = m_master.GetContextMetadata(&To->getASTContext());
if (!to_context_md)
- return NULL;
+ return nullptr;
OriginMap::iterator iter = to_context_md->m_origins.find(To);
if (iter == to_context_md->m_origins.end())
- return NULL;
+ return nullptr;
return const_cast<clang::Decl*>(iter->second.decl);
}
diff --git a/source/Symbol/ClangASTType.cpp b/source/Symbol/ClangASTType.cpp
index 40f6462ee360..a0878ae442c8 100644
--- a/source/Symbol/ClangASTType.cpp
+++ b/source/Symbol/ClangASTType.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
+#include "clang/AST/VTableBuilder.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
@@ -50,11 +51,9 @@
using namespace lldb;
using namespace lldb_private;
-using namespace clang;
-using namespace llvm;
static bool
-GetCompleteQualType (ASTContext *ast, QualType qual_type, bool allow_completion = true)
+GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type, bool allow_completion = true)
{
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
@@ -63,7 +62,7 @@ GetCompleteQualType (ASTContext *ast, QualType qual_type, bool allow_completion
case clang::Type::IncompleteArray:
case clang::Type::VariableArray:
{
- const ArrayType *array_type = dyn_cast<ArrayType>(qual_type.getTypePtr());
+ const clang::ArrayType *array_type = llvm::dyn_cast<clang::ArrayType>(qual_type.getTypePtr());
if (array_type)
return GetCompleteQualType (ast, array_type->getElementType(), allow_completion);
@@ -73,10 +72,10 @@ GetCompleteQualType (ASTContext *ast, QualType qual_type, bool allow_completion
case clang::Type::Record:
case clang::Type::Enum:
{
- const TagType *tag_type = dyn_cast<TagType>(qual_type.getTypePtr());
+ const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
if (tag_type)
{
- TagDecl *tag_decl = tag_type->getDecl();
+ clang::TagDecl *tag_decl = tag_type->getDecl();
if (tag_decl)
{
if (tag_decl->isCompleteDefinition())
@@ -89,7 +88,7 @@ GetCompleteQualType (ASTContext *ast, QualType qual_type, bool allow_completion
{
if (ast)
{
- ExternalASTSource *external_ast_source = ast->getExternalSource();
+ clang::ExternalASTSource *external_ast_source = ast->getExternalSource();
if (external_ast_source)
{
external_ast_source->CompleteType(tag_decl);
@@ -107,10 +106,10 @@ GetCompleteQualType (ASTContext *ast, QualType qual_type, bool allow_completion
case clang::Type::ObjCObject:
case clang::Type::ObjCInterface:
{
- const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type);
+ const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
if (objc_class_type)
{
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
// We currently can't complete objective C types through the newly added ASTContext
// because it only supports TagDecl objects right now...
if (class_interface_decl)
@@ -125,7 +124,7 @@ GetCompleteQualType (ASTContext *ast, QualType qual_type, bool allow_completion
{
if (ast)
{
- ExternalASTSource *external_ast_source = ast->getExternalSource();
+ clang::ExternalASTSource *external_ast_source = ast->getExternalSource();
if (external_ast_source)
{
external_ast_source->CompleteType (class_interface_decl);
@@ -140,13 +139,13 @@ GetCompleteQualType (ASTContext *ast, QualType qual_type, bool allow_completion
break;
case clang::Type::Typedef:
- return GetCompleteQualType (ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType(), allow_completion);
+ return GetCompleteQualType (ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType(), allow_completion);
case clang::Type::Elaborated:
- return GetCompleteQualType (ast, cast<ElaboratedType>(qual_type)->getNamedType(), allow_completion);
+ return GetCompleteQualType (ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType(), allow_completion);
case clang::Type::Paren:
- return GetCompleteQualType (ast, cast<ParenType>(qual_type)->desugar(), allow_completion);
+ return GetCompleteQualType (ast, llvm::cast<clang::ParenType>(qual_type)->desugar(), allow_completion);
default:
break;
@@ -155,18 +154,18 @@ GetCompleteQualType (ASTContext *ast, QualType qual_type, bool allow_completion
return true;
}
-static ObjCIvarDecl::AccessControl
+static clang::ObjCIvarDecl::AccessControl
ConvertAccessTypeToObjCIvarAccessControl (AccessType access)
{
switch (access)
{
- case eAccessNone: return ObjCIvarDecl::None;
- case eAccessPublic: return ObjCIvarDecl::Public;
- case eAccessPrivate: return ObjCIvarDecl::Private;
- case eAccessProtected: return ObjCIvarDecl::Protected;
- case eAccessPackage: return ObjCIvarDecl::Package;
+ case eAccessNone: return clang::ObjCIvarDecl::None;
+ case eAccessPublic: return clang::ObjCIvarDecl::Public;
+ case eAccessPrivate: return clang::ObjCIvarDecl::Private;
+ case eAccessProtected: return clang::ObjCIvarDecl::Protected;
+ case eAccessPackage: return clang::ObjCIvarDecl::Package;
}
- return ObjCIvarDecl::None;
+ return clang::ObjCIvarDecl::None;
}
//----------------------------------------------------------------------
@@ -194,7 +193,7 @@ ClangASTType::IsAggregateType () const
if (!IsValid())
return false;
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
@@ -209,11 +208,11 @@ ClangASTType::IsAggregateType () const
case clang::Type::ObjCInterface:
return true;
case clang::Type::Elaborated:
- return ClangASTType(m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsAggregateType();
+ return ClangASTType(m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).IsAggregateType();
case clang::Type::Typedef:
- return ClangASTType(m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsAggregateType();
+ return ClangASTType(m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsAggregateType();
case clang::Type::Paren:
- return ClangASTType(m_ast, cast<ParenType>(qual_type)->desugar()).IsAggregateType();
+ return ClangASTType(m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).IsAggregateType();
default:
break;
}
@@ -228,7 +227,7 @@ ClangASTType::IsArrayType (ClangASTType *element_type_ptr,
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
@@ -238,14 +237,14 @@ ClangASTType::IsArrayType (ClangASTType *element_type_ptr,
case clang::Type::ConstantArray:
if (element_type_ptr)
- element_type_ptr->SetClangType (m_ast, cast<ConstantArrayType>(qual_type)->getElementType());
+ element_type_ptr->SetClangType (m_ast, llvm::cast<clang::ConstantArrayType>(qual_type)->getElementType());
if (size)
- *size = cast<ConstantArrayType>(qual_type)->getSize().getLimitedValue(ULLONG_MAX);
+ *size = llvm::cast<clang::ConstantArrayType>(qual_type)->getSize().getLimitedValue(ULLONG_MAX);
return true;
case clang::Type::IncompleteArray:
if (element_type_ptr)
- element_type_ptr->SetClangType (m_ast, cast<IncompleteArrayType>(qual_type)->getElementType());
+ element_type_ptr->SetClangType (m_ast, llvm::cast<clang::IncompleteArrayType>(qual_type)->getElementType());
if (size)
*size = 0;
if (is_incomplete)
@@ -254,28 +253,28 @@ ClangASTType::IsArrayType (ClangASTType *element_type_ptr,
case clang::Type::VariableArray:
if (element_type_ptr)
- element_type_ptr->SetClangType (m_ast, cast<VariableArrayType>(qual_type)->getElementType());
+ element_type_ptr->SetClangType (m_ast, llvm::cast<clang::VariableArrayType>(qual_type)->getElementType());
if (size)
*size = 0;
return true;
case clang::Type::DependentSizedArray:
if (element_type_ptr)
- element_type_ptr->SetClangType (m_ast, cast<DependentSizedArrayType>(qual_type)->getElementType());
+ element_type_ptr->SetClangType (m_ast, llvm::cast<clang::DependentSizedArrayType>(qual_type)->getElementType());
if (size)
*size = 0;
return true;
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsArrayType (element_type_ptr,
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsArrayType (element_type_ptr,
size,
is_incomplete);
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsArrayType (element_type_ptr,
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).IsArrayType (element_type_ptr,
size,
is_incomplete);
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).IsArrayType (element_type_ptr,
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).IsArrayType (element_type_ptr,
size,
is_incomplete);
}
@@ -352,7 +351,7 @@ ClangASTType::IsCStringType (uint32_t &length) const
{
// We know the size of the array and it could be a C string
// since it is an array of characters
- length = cast<ConstantArrayType>(GetCanonicalQualType().getTypePtr())->getSize().getLimitedValue();
+ length = llvm::cast<clang::ConstantArrayType>(GetCanonicalQualType().getTypePtr())->getSize().getLimitedValue();
}
return true;
@@ -366,7 +365,7 @@ ClangASTType::IsFunctionType (bool *is_variadic_ptr) const
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
if (qual_type->isFunctionType())
{
@@ -387,16 +386,16 @@ ClangASTType::IsFunctionType (bool *is_variadic_ptr) const
default:
break;
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsFunctionType();
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsFunctionType();
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsFunctionType();
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).IsFunctionType();
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).IsFunctionType();
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).IsFunctionType();
case clang::Type::LValueReference:
case clang::Type::RValueReference:
{
- const ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
+ const clang::ReferenceType *reference_type = llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
if (reference_type)
return ClangASTType (m_ast, reference_type->getPointeeType()).IsFunctionType();
}
@@ -406,13 +405,109 @@ ClangASTType::IsFunctionType (bool *is_variadic_ptr) const
return false;
}
+// Used to detect "Homogeneous Floating-point Aggregates"
+uint32_t
+ClangASTType::IsHomogeneousAggregate (ClangASTType* base_type_ptr) const
+{
+ if (!IsValid())
+ return 0;
+
+ clang::QualType qual_type(GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Record:
+ if (GetCompleteType ())
+ {
+ const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl)
+ {
+ if (cxx_record_decl->getNumBases() ||
+ cxx_record_decl->isDynamicClass())
+ return 0;
+ }
+ const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ if (record_type)
+ {
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ if (record_decl)
+ {
+ // We are looking for a structure that contains only floating point types
+ clang::RecordDecl::field_iterator field_pos, field_end = record_decl->field_end();
+ uint32_t num_fields = 0;
+ bool is_hva = false;
+ bool is_hfa = false;
+ clang::QualType base_qual_type;
+ for (field_pos = record_decl->field_begin(); field_pos != field_end; ++field_pos)
+ {
+ clang::QualType field_qual_type = field_pos->getType();
+ if (field_qual_type->isFloatingType())
+ {
+ if (field_qual_type->isComplexType())
+ return 0;
+ else
+ {
+ if (num_fields == 0)
+ base_qual_type = field_qual_type;
+ else
+ {
+ if (is_hva)
+ return 0;
+ is_hfa = true;
+ if (field_qual_type.getTypePtr() != base_qual_type.getTypePtr())
+ return 0;
+ }
+ }
+ }
+ else if (field_qual_type->isVectorType() || field_qual_type->isExtVectorType())
+ {
+ const clang::VectorType *array = llvm::cast<clang::VectorType>(field_qual_type.getTypePtr());
+ if (array && array->getNumElements() <= 4)
+ {
+ if (num_fields == 0)
+ base_qual_type = array->getElementType();
+ else
+ {
+ if (is_hfa)
+ return 0;
+ is_hva = true;
+ if (field_qual_type.getTypePtr() != base_qual_type.getTypePtr())
+ return 0;
+ }
+ }
+ else
+ return 0;
+ }
+ else
+ return 0;
+ ++num_fields;
+ }
+ if (base_type_ptr)
+ *base_type_ptr = ClangASTType (m_ast, base_qual_type);
+ return num_fields;
+ }
+ }
+ }
+ break;
+
+ case clang::Type::Typedef:
+ return ClangASTType(m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsHomogeneousAggregate (base_type_ptr);
+
+ case clang::Type::Elaborated:
+ return ClangASTType(m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).IsHomogeneousAggregate (base_type_ptr);
+ default:
+ break;
+ }
+ return 0;
+}
+
size_t
ClangASTType::GetNumberOfFunctionArguments () const
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
- const FunctionProtoType* func = dyn_cast<FunctionProtoType>(qual_type.getTypePtr());
+ clang::QualType qual_type (GetCanonicalQualType());
+ const clang::FunctionProtoType* func = llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr());
if (func)
return func->getNumParams();
}
@@ -424,8 +519,8 @@ ClangASTType::GetFunctionArgumentAtIndex (const size_t index)
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
- const FunctionProtoType* func = dyn_cast<FunctionProtoType>(qual_type.getTypePtr());
+ clang::QualType qual_type (GetCanonicalQualType());
+ const clang::FunctionProtoType* func = llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr());
if (func)
{
if (index < func->getNumParams())
@@ -440,7 +535,7 @@ ClangASTType::IsFunctionPointerType () const
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
if (qual_type->isFunctionPointerType())
return true;
@@ -451,16 +546,16 @@ ClangASTType::IsFunctionPointerType () const
default:
break;
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsFunctionPointerType();
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsFunctionPointerType();
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsFunctionPointerType();
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).IsFunctionPointerType();
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).IsFunctionPointerType();
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).IsFunctionPointerType();
case clang::Type::LValueReference:
case clang::Type::RValueReference:
{
- const ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
+ const clang::ReferenceType *reference_type = llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
if (reference_type)
return ClangASTType (m_ast, reference_type->getPointeeType()).IsFunctionPointerType();
}
@@ -477,8 +572,8 @@ ClangASTType::IsIntegerType (bool &is_signed) const
if (!IsValid())
return false;
- QualType qual_type (GetCanonicalQualType());
- const BuiltinType *builtin_type = dyn_cast<BuiltinType>(qual_type->getCanonicalTypeInternal());
+ clang::QualType qual_type (GetCanonicalQualType());
+ const clang::BuiltinType *builtin_type = llvm::dyn_cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal());
if (builtin_type)
{
@@ -497,12 +592,12 @@ ClangASTType::IsPointerType (ClangASTType *pointee_type) const
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Builtin:
- switch (cast<clang::BuiltinType>(qual_type)->getKind())
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind())
{
default:
break;
@@ -513,26 +608,26 @@ ClangASTType::IsPointerType (ClangASTType *pointee_type) const
return false;
case clang::Type::ObjCObjectPointer:
if (pointee_type)
- pointee_type->SetClangType (m_ast, cast<ObjCObjectPointerType>(qual_type)->getPointeeType());
+ pointee_type->SetClangType (m_ast, llvm::cast<clang::ObjCObjectPointerType>(qual_type)->getPointeeType());
return true;
case clang::Type::BlockPointer:
if (pointee_type)
- pointee_type->SetClangType (m_ast, cast<BlockPointerType>(qual_type)->getPointeeType());
+ pointee_type->SetClangType (m_ast, llvm::cast<clang::BlockPointerType>(qual_type)->getPointeeType());
return true;
case clang::Type::Pointer:
if (pointee_type)
- pointee_type->SetClangType (m_ast, cast<PointerType>(qual_type)->getPointeeType());
+ pointee_type->SetClangType (m_ast, llvm::cast<clang::PointerType>(qual_type)->getPointeeType());
return true;
case clang::Type::MemberPointer:
if (pointee_type)
- pointee_type->SetClangType (m_ast, cast<MemberPointerType>(qual_type)->getPointeeType());
+ pointee_type->SetClangType (m_ast, llvm::cast<clang::MemberPointerType>(qual_type)->getPointeeType());
return true;
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsPointerType(pointee_type);
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsPointerType(pointee_type);
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsPointerType(pointee_type);
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).IsPointerType(pointee_type);
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).IsPointerType(pointee_type);
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).IsPointerType(pointee_type);
default:
break;
}
@@ -548,12 +643,12 @@ ClangASTType::IsPointerOrReferenceType (ClangASTType *pointee_type) const
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Builtin:
- switch (cast<clang::BuiltinType>(qual_type)->getKind())
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind())
{
default:
break;
@@ -564,34 +659,34 @@ ClangASTType::IsPointerOrReferenceType (ClangASTType *pointee_type) const
return false;
case clang::Type::ObjCObjectPointer:
if (pointee_type)
- pointee_type->SetClangType(m_ast, cast<ObjCObjectPointerType>(qual_type)->getPointeeType());
+ pointee_type->SetClangType(m_ast, llvm::cast<clang::ObjCObjectPointerType>(qual_type)->getPointeeType());
return true;
case clang::Type::BlockPointer:
if (pointee_type)
- pointee_type->SetClangType(m_ast, cast<BlockPointerType>(qual_type)->getPointeeType());
+ pointee_type->SetClangType(m_ast, llvm::cast<clang::BlockPointerType>(qual_type)->getPointeeType());
return true;
case clang::Type::Pointer:
if (pointee_type)
- pointee_type->SetClangType(m_ast, cast<PointerType>(qual_type)->getPointeeType());
+ pointee_type->SetClangType(m_ast, llvm::cast<clang::PointerType>(qual_type)->getPointeeType());
return true;
case clang::Type::MemberPointer:
if (pointee_type)
- pointee_type->SetClangType(m_ast, cast<MemberPointerType>(qual_type)->getPointeeType());
+ pointee_type->SetClangType(m_ast, llvm::cast<clang::MemberPointerType>(qual_type)->getPointeeType());
return true;
case clang::Type::LValueReference:
if (pointee_type)
- pointee_type->SetClangType(m_ast, cast<LValueReferenceType>(qual_type)->desugar());
+ pointee_type->SetClangType(m_ast, llvm::cast<clang::LValueReferenceType>(qual_type)->desugar());
return true;
case clang::Type::RValueReference:
if (pointee_type)
- pointee_type->SetClangType(m_ast, cast<LValueReferenceType>(qual_type)->desugar());
+ pointee_type->SetClangType(m_ast, llvm::cast<clang::RValueReferenceType>(qual_type)->desugar());
return true;
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsPointerOrReferenceType(pointee_type);
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsPointerOrReferenceType(pointee_type);
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsPointerOrReferenceType(pointee_type);
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).IsPointerOrReferenceType(pointee_type);
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).IsPointerOrReferenceType(pointee_type);
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).IsPointerOrReferenceType(pointee_type);
default:
break;
}
@@ -603,29 +698,33 @@ ClangASTType::IsPointerOrReferenceType (ClangASTType *pointee_type) const
bool
-ClangASTType::IsReferenceType (ClangASTType *pointee_type) const
+ClangASTType::IsReferenceType (ClangASTType *pointee_type, bool* is_rvalue) const
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::LValueReference:
if (pointee_type)
- pointee_type->SetClangType(m_ast, cast<LValueReferenceType>(qual_type)->desugar());
+ pointee_type->SetClangType(m_ast, llvm::cast<clang::LValueReferenceType>(qual_type)->desugar());
+ if (is_rvalue)
+ *is_rvalue = false;
return true;
case clang::Type::RValueReference:
if (pointee_type)
- pointee_type->SetClangType(m_ast, cast<LValueReferenceType>(qual_type)->desugar());
+ pointee_type->SetClangType(m_ast, llvm::cast<clang::RValueReferenceType>(qual_type)->desugar());
+ if (is_rvalue)
+ *is_rvalue = true;
return true;
case clang::Type::Typedef:
- return ClangASTType(m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsReferenceType(pointee_type);
+ return ClangASTType(m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsReferenceType(pointee_type, is_rvalue);
case clang::Type::Elaborated:
- return ClangASTType(m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsReferenceType(pointee_type);
+ return ClangASTType(m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).IsReferenceType(pointee_type, is_rvalue);
case clang::Type::Paren:
- return ClangASTType(m_ast, cast<clang::ParenType>(qual_type)->desugar()).IsReferenceType(pointee_type);
+ return ClangASTType(m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).IsReferenceType(pointee_type, is_rvalue);
default:
break;
@@ -641,19 +740,19 @@ ClangASTType::IsFloatingPointType (uint32_t &count, bool &is_complex) const
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
- if (const BuiltinType *BT = dyn_cast<BuiltinType>(qual_type->getCanonicalTypeInternal()))
+ if (const clang::BuiltinType *BT = llvm::dyn_cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal()))
{
clang::BuiltinType::Kind kind = BT->getKind();
- if (kind >= BuiltinType::Float && kind <= BuiltinType::LongDouble)
+ if (kind >= clang::BuiltinType::Float && kind <= clang::BuiltinType::LongDouble)
{
count = 1;
is_complex = false;
return true;
}
}
- else if (const ComplexType *CT = dyn_cast<ComplexType>(qual_type->getCanonicalTypeInternal()))
+ else if (const clang::ComplexType *CT = llvm::dyn_cast<clang::ComplexType>(qual_type->getCanonicalTypeInternal()))
{
if (ClangASTType (m_ast, CT->getElementType()).IsFloatingPointType (count, is_complex))
{
@@ -662,7 +761,7 @@ ClangASTType::IsFloatingPointType (uint32_t &count, bool &is_complex) const
return true;
}
}
- else if (const VectorType *VT = dyn_cast<VectorType>(qual_type->getCanonicalTypeInternal()))
+ else if (const clang::VectorType *VT = llvm::dyn_cast<clang::VectorType>(qual_type->getCanonicalTypeInternal()))
{
if (ClangASTType (m_ast, VT->getElementType()).IsFloatingPointType (count, is_complex))
{
@@ -684,23 +783,23 @@ ClangASTType::IsDefined() const
if (!IsValid())
return false;
- QualType qual_type(GetQualType());
- const TagType *tag_type = dyn_cast<TagType>(qual_type.getTypePtr());
+ clang::QualType qual_type(GetQualType());
+ const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
if (tag_type)
{
- TagDecl *tag_decl = tag_type->getDecl();
+ clang::TagDecl *tag_decl = tag_type->getDecl();
if (tag_decl)
return tag_decl->isCompleteDefinition();
return false;
}
else
{
- const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type);
+ const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
if (objc_class_type)
{
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
if (class_interface_decl)
- return class_interface_decl->getDefinition() != NULL;
+ return class_interface_decl->getDefinition() != nullptr;
return false;
}
}
@@ -712,9 +811,9 @@ ClangASTType::IsObjCClassType () const
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
- const ObjCObjectPointerType *obj_pointer_type = dyn_cast<ObjCObjectPointerType>(qual_type);
+ const clang::ObjCObjectPointerType *obj_pointer_type = llvm::dyn_cast<clang::ObjCObjectPointerType>(qual_type);
if (obj_pointer_type)
return obj_pointer_type->isObjCClassType();
@@ -735,18 +834,18 @@ ClangASTType::IsPolymorphicClass () const
{
if (IsValid())
{
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Record:
if (GetCompleteType())
{
- const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
- const RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
if (record_decl)
{
- const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
if (cxx_record_decl)
return cxx_record_decl->isPolymorphic();
}
@@ -765,16 +864,16 @@ ClangASTType::IsPossibleDynamicType (ClangASTType *dynamic_pointee_type,
bool check_cplusplus,
bool check_objc) const
{
- QualType pointee_qual_type;
+ clang::QualType pointee_qual_type;
if (m_type)
{
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
bool success = false;
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Builtin:
- if (check_objc && cast<BuiltinType>(qual_type)->getKind() == BuiltinType::ObjCId)
+ if (check_objc && llvm::cast<clang::BuiltinType>(qual_type)->getKind() == clang::BuiltinType::ObjCId)
{
if (dynamic_pointee_type)
dynamic_pointee_type->SetClangType(m_ast, m_type);
@@ -786,37 +885,37 @@ ClangASTType::IsPossibleDynamicType (ClangASTType *dynamic_pointee_type,
if (check_objc)
{
if (dynamic_pointee_type)
- dynamic_pointee_type->SetClangType(m_ast, cast<ObjCObjectPointerType>(qual_type)->getPointeeType());
+ dynamic_pointee_type->SetClangType(m_ast, llvm::cast<clang::ObjCObjectPointerType>(qual_type)->getPointeeType());
return true;
}
break;
case clang::Type::Pointer:
- pointee_qual_type = cast<PointerType>(qual_type)->getPointeeType();
+ pointee_qual_type = llvm::cast<clang::PointerType>(qual_type)->getPointeeType();
success = true;
break;
case clang::Type::LValueReference:
case clang::Type::RValueReference:
- pointee_qual_type = cast<ReferenceType>(qual_type)->getPointeeType();
+ pointee_qual_type = llvm::cast<clang::ReferenceType>(qual_type)->getPointeeType();
success = true;
break;
case clang::Type::Typedef:
return ClangASTType (m_ast,
- cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsPossibleDynamicType (dynamic_pointee_type,
+ llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsPossibleDynamicType (dynamic_pointee_type,
check_cplusplus,
check_objc);
case clang::Type::Elaborated:
return ClangASTType (m_ast,
- cast<ElaboratedType>(qual_type)->getNamedType()).IsPossibleDynamicType (dynamic_pointee_type,
+ llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).IsPossibleDynamicType (dynamic_pointee_type,
check_cplusplus,
check_objc);
case clang::Type::Paren:
return ClangASTType (m_ast,
- cast<ParenType>(qual_type)->desugar()).IsPossibleDynamicType (dynamic_pointee_type,
+ llvm::cast<clang::ParenType>(qual_type)->desugar()).IsPossibleDynamicType (dynamic_pointee_type,
check_cplusplus,
check_objc);
default:
@@ -832,55 +931,55 @@ ClangASTType::IsPossibleDynamicType (ClangASTType *dynamic_pointee_type,
switch (pointee_type_class)
{
case clang::Type::Builtin:
- switch (cast<BuiltinType>(pointee_qual_type)->getKind())
+ switch (llvm::cast<clang::BuiltinType>(pointee_qual_type)->getKind())
{
- case BuiltinType::UnknownAny:
- case BuiltinType::Void:
+ case clang::BuiltinType::UnknownAny:
+ case clang::BuiltinType::Void:
if (dynamic_pointee_type)
dynamic_pointee_type->SetClangType(m_ast, pointee_qual_type);
return true;
- case BuiltinType::NullPtr:
- case BuiltinType::Bool:
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- case BuiltinType::WChar_U:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::UShort:
- case BuiltinType::UInt:
- case BuiltinType::ULong:
- case BuiltinType::ULongLong:
- case BuiltinType::UInt128:
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- case BuiltinType::WChar_S:
- case BuiltinType::Short:
- case BuiltinType::Int:
- case BuiltinType::Long:
- case BuiltinType::LongLong:
- case BuiltinType::Int128:
- case BuiltinType::Float:
- case BuiltinType::Double:
- case BuiltinType::LongDouble:
- case BuiltinType::Dependent:
- case BuiltinType::Overload:
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCSel:
- case BuiltinType::BoundMember:
- case BuiltinType::Half:
- case BuiltinType::ARCUnbridgedCast:
- case BuiltinType::PseudoObject:
- case BuiltinType::BuiltinFn:
- case BuiltinType::OCLEvent:
- case BuiltinType::OCLImage1d:
- case BuiltinType::OCLImage1dArray:
- case BuiltinType::OCLImage1dBuffer:
- case BuiltinType::OCLImage2d:
- case BuiltinType::OCLImage2dArray:
- case BuiltinType::OCLImage3d:
- case BuiltinType::OCLSampler:
+ case clang::BuiltinType::NullPtr:
+ case clang::BuiltinType::Bool:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::WChar_U:
+ case clang::BuiltinType::Char16:
+ case clang::BuiltinType::Char32:
+ case clang::BuiltinType::UShort:
+ case clang::BuiltinType::UInt:
+ case clang::BuiltinType::ULong:
+ case clang::BuiltinType::ULongLong:
+ case clang::BuiltinType::UInt128:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::WChar_S:
+ case clang::BuiltinType::Short:
+ case clang::BuiltinType::Int:
+ case clang::BuiltinType::Long:
+ case clang::BuiltinType::LongLong:
+ case clang::BuiltinType::Int128:
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::LongDouble:
+ case clang::BuiltinType::Dependent:
+ case clang::BuiltinType::Overload:
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ case clang::BuiltinType::ObjCSel:
+ case clang::BuiltinType::BoundMember:
+ case clang::BuiltinType::Half:
+ case clang::BuiltinType::ARCUnbridgedCast:
+ case clang::BuiltinType::PseudoObject:
+ case clang::BuiltinType::BuiltinFn:
+ case clang::BuiltinType::OCLEvent:
+ case clang::BuiltinType::OCLImage1d:
+ case clang::BuiltinType::OCLImage1dArray:
+ case clang::BuiltinType::OCLImage1dBuffer:
+ case clang::BuiltinType::OCLImage2d:
+ case clang::BuiltinType::OCLImage2dArray:
+ case clang::BuiltinType::OCLImage3d:
+ case clang::BuiltinType::OCLSampler:
break;
}
break;
@@ -888,7 +987,7 @@ ClangASTType::IsPossibleDynamicType (ClangASTType *dynamic_pointee_type,
case clang::Type::Record:
if (check_cplusplus)
{
- CXXRecordDecl *cxx_record_decl = pointee_qual_type->getAsCXXRecordDecl();
+ clang::CXXRecordDecl *cxx_record_decl = pointee_qual_type->getAsCXXRecordDecl();
if (cxx_record_decl)
{
bool is_complete = cxx_record_decl->isCompleteDefinition();
@@ -947,7 +1046,7 @@ ClangASTType::IsScalarType () const
if (!IsValid())
return false;
- return (GetTypeInfo (NULL) & eTypeIsScalar) != 0;
+ return (GetTypeInfo (nullptr) & eTypeIsScalar) != 0;
}
bool
@@ -979,7 +1078,7 @@ bool
ClangASTType::IsArrayOfScalarType () const
{
ClangASTType element_type;
- if (IsArrayType(&element_type, NULL, NULL))
+ if (IsArrayType(&element_type, nullptr, nullptr))
return element_type.IsScalarType();
return false;
}
@@ -990,9 +1089,9 @@ ClangASTType::GetCXXClassName (std::string &class_name) const
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
- CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
if (cxx_record_decl)
{
class_name.assign (cxx_record_decl->getIdentifier()->getNameStart());
@@ -1010,8 +1109,8 @@ ClangASTType::IsCXXClassType () const
if (!IsValid())
return false;
- QualType qual_type (GetCanonicalQualType());
- if (qual_type->getAsCXXRecordDecl() != NULL)
+ clang::QualType qual_type (GetCanonicalQualType());
+ if (qual_type->getAsCXXRecordDecl() != nullptr)
return true;
return false;
}
@@ -1021,8 +1120,8 @@ ClangASTType::IsBeingDefined () const
{
if (!IsValid())
return false;
- QualType qual_type (GetCanonicalQualType());
- const clang::TagType *tag_type = dyn_cast<clang::TagType>(qual_type);
+ clang::QualType qual_type (GetCanonicalQualType());
+ const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type);
if (tag_type)
return tag_type->isBeingDefined();
return false;
@@ -1034,7 +1133,7 @@ ClangASTType::IsObjCObjectPointerType (ClangASTType *class_type_ptr)
if (!IsValid())
return false;
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
if (qual_type->isObjCObjectPointerType())
{
@@ -1043,11 +1142,11 @@ ClangASTType::IsObjCObjectPointerType (ClangASTType *class_type_ptr)
if (!qual_type->isObjCClassType() &&
!qual_type->isObjCIdType())
{
- const ObjCObjectPointerType *obj_pointer_type = dyn_cast<ObjCObjectPointerType>(qual_type);
- if (obj_pointer_type == NULL)
+ const clang::ObjCObjectPointerType *obj_pointer_type = llvm::dyn_cast<clang::ObjCObjectPointerType>(qual_type);
+ if (obj_pointer_type == nullptr)
class_type_ptr->Clear();
else
- class_type_ptr->SetClangType (m_ast, QualType(obj_pointer_type->getInterfaceType(), 0));
+ class_type_ptr->SetClangType (m_ast, clang::QualType(obj_pointer_type->getInterfaceType(), 0));
}
}
return true;
@@ -1063,12 +1162,12 @@ ClangASTType::GetObjCClassName (std::string &class_name)
if (!IsValid())
return false;
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
- const ObjCObjectType *object_type = dyn_cast<ObjCObjectType>(qual_type);
+ const clang::ObjCObjectType *object_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
if (object_type)
{
- const ObjCInterfaceDecl *interface = object_type->getInterface();
+ const clang::ObjCInterfaceDecl *interface = object_type->getInterface();
if (interface)
{
class_name = interface->getNameAsString();
@@ -1127,14 +1226,14 @@ ClangASTType::GetTypeName () const
std::string type_name;
if (IsValid())
{
- PrintingPolicy printing_policy (m_ast->getPrintingPolicy());
- QualType qual_type(GetQualType());
+ clang::PrintingPolicy printing_policy (m_ast->getPrintingPolicy());
+ clang::QualType qual_type(GetQualType());
printing_policy.SuppressTagKeyword = true;
printing_policy.LangOpts.WChar = true;
- const TypedefType *typedef_type = qual_type->getAs<TypedefType>();
+ const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>();
if (typedef_type)
{
- const TypedefNameDecl *typedef_decl = typedef_type->getDecl();
+ const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl();
type_name = typedef_decl->getQualifiedNameAsString();
}
else
@@ -1145,6 +1244,11 @@ ClangASTType::GetTypeName () const
return ConstString(type_name);
}
+ConstString
+ClangASTType::GetDisplayTypeName () const
+{
+ return GetTypeName();
+}
uint32_t
ClangASTType::GetTypeInfo (ClangASTType *pointee_or_element_clang_type) const
@@ -1155,14 +1259,14 @@ ClangASTType::GetTypeInfo (ClangASTType *pointee_or_element_clang_type) const
if (pointee_or_element_clang_type)
pointee_or_element_clang_type->Clear();
- QualType qual_type (GetQualType());
+ clang::QualType qual_type (GetQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Builtin:
{
- const BuiltinType *builtin_type = dyn_cast<BuiltinType>(qual_type->getCanonicalTypeInternal());
+ const clang::BuiltinType *builtin_type = llvm::dyn_cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal());
uint32_t builtin_type_flags = eTypeIsBuiltIn | eTypeHasValue;
switch (builtin_type->getKind())
@@ -1226,10 +1330,10 @@ ClangASTType::GetTypeInfo (ClangASTType *pointee_or_element_clang_type) const
case clang::Type::Complex:
{
uint32_t complex_type_flags = eTypeIsBuiltIn | eTypeHasValue | eTypeIsComplex;
- const ComplexType *complex_type = dyn_cast<ComplexType>(qual_type->getCanonicalTypeInternal());
+ const clang::ComplexType *complex_type = llvm::dyn_cast<clang::ComplexType>(qual_type->getCanonicalTypeInternal());
if (complex_type)
{
- QualType complex_element_type (complex_type->getElementType());
+ clang::QualType complex_element_type (complex_type->getElementType());
if (complex_element_type->isIntegerType())
complex_type_flags |= eTypeIsFloat;
else if (complex_element_type->isFloatingType())
@@ -1244,7 +1348,7 @@ ClangASTType::GetTypeInfo (ClangASTType *pointee_or_element_clang_type) const
case clang::Type::IncompleteArray:
case clang::Type::VariableArray:
if (pointee_or_element_clang_type)
- pointee_or_element_clang_type->SetClangType(m_ast, cast<ArrayType>(qual_type.getTypePtr())->getElementType());
+ pointee_or_element_clang_type->SetClangType(m_ast, llvm::cast<clang::ArrayType>(qual_type.getTypePtr())->getElementType());
return eTypeHasChildren | eTypeIsArray;
case clang::Type::DependentName: return 0;
@@ -1254,13 +1358,13 @@ ClangASTType::GetTypeInfo (ClangASTType *pointee_or_element_clang_type) const
case clang::Type::Enum:
if (pointee_or_element_clang_type)
- pointee_or_element_clang_type->SetClangType(m_ast, cast<EnumType>(qual_type)->getDecl()->getIntegerType());
+ pointee_or_element_clang_type->SetClangType(m_ast, llvm::cast<clang::EnumType>(qual_type)->getDecl()->getIntegerType());
return eTypeIsEnumeration | eTypeHasValue;
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetTypeInfo (pointee_or_element_clang_type);
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetTypeInfo (pointee_or_element_clang_type);
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetTypeInfo (pointee_or_element_clang_type);
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetTypeInfo (pointee_or_element_clang_type);
case clang::Type::FunctionProto: return eTypeIsFuncPrototype | eTypeHasValue;
case clang::Type::FunctionNoProto: return eTypeIsFuncPrototype | eTypeHasValue;
@@ -1269,7 +1373,7 @@ ClangASTType::GetTypeInfo (ClangASTType *pointee_or_element_clang_type) const
case clang::Type::LValueReference:
case clang::Type::RValueReference:
if (pointee_or_element_clang_type)
- pointee_or_element_clang_type->SetClangType(m_ast, cast<ReferenceType>(qual_type.getTypePtr())->getPointeeType());
+ pointee_or_element_clang_type->SetClangType(m_ast, llvm::cast<clang::ReferenceType>(qual_type.getTypePtr())->getPointeeType());
return eTypeHasChildren | eTypeIsReference | eTypeHasValue;
case clang::Type::MemberPointer: return eTypeIsPointer | eTypeIsMember | eTypeHasValue;
@@ -1298,7 +1402,7 @@ ClangASTType::GetTypeInfo (ClangASTType *pointee_or_element_clang_type) const
case clang::Type::TemplateSpecialization: return eTypeIsTemplate;
case clang::Type::Typedef:
- return eTypeIsTypedef | ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetTypeInfo (pointee_or_element_clang_type);
+ return eTypeIsTypedef | ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetTypeInfo (pointee_or_element_clang_type);
case clang::Type::TypeOfExpr: return 0;
case clang::Type::TypeOf: return 0;
case clang::Type::UnresolvedUsing: return 0;
@@ -1307,7 +1411,7 @@ ClangASTType::GetTypeInfo (ClangASTType *pointee_or_element_clang_type) const
case clang::Type::Vector:
{
uint32_t vector_type_flags = eTypeHasChildren | eTypeIsVector;
- const VectorType *vector_type = dyn_cast<VectorType>(qual_type->getCanonicalTypeInternal());
+ const clang::VectorType *vector_type = llvm::dyn_cast<clang::VectorType>(qual_type->getCanonicalTypeInternal());
if (vector_type)
{
if (vector_type->isIntegerType())
@@ -1331,14 +1435,14 @@ ClangASTType::GetMinimumLanguage ()
return lldb::eLanguageTypeC;
// If the type is a reference, then resolve it to what it refers to first:
- QualType qual_type (GetCanonicalQualType().getNonReferenceType());
+ clang::QualType qual_type (GetCanonicalQualType().getNonReferenceType());
if (qual_type->isAnyPointerType())
{
if (qual_type->isObjCObjectPointerType())
return lldb::eLanguageTypeObjC;
- QualType pointee_type (qual_type->getPointeeType());
- if (pointee_type->getPointeeCXXRecordDecl() != NULL)
+ clang::QualType pointee_type (qual_type->getPointeeType());
+ if (pointee_type->getPointeeCXXRecordDecl() != nullptr)
return lldb::eLanguageTypeC_plus_plus;
if (pointee_type->isObjCObjectOrInterfaceType())
return lldb::eLanguageTypeObjC;
@@ -1358,51 +1462,51 @@ ClangASTType::GetMinimumLanguage ()
default:
break;
case clang::Type::Builtin:
- switch (cast<BuiltinType>(qual_type)->getKind())
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind())
{
default:
- case BuiltinType::Void:
- case BuiltinType::Bool:
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- case BuiltinType::WChar_U:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::UShort:
- case BuiltinType::UInt:
- case BuiltinType::ULong:
- case BuiltinType::ULongLong:
- case BuiltinType::UInt128:
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- case BuiltinType::WChar_S:
- case BuiltinType::Short:
- case BuiltinType::Int:
- case BuiltinType::Long:
- case BuiltinType::LongLong:
- case BuiltinType::Int128:
- case BuiltinType::Float:
- case BuiltinType::Double:
- case BuiltinType::LongDouble:
+ case clang::BuiltinType::Void:
+ case clang::BuiltinType::Bool:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::WChar_U:
+ case clang::BuiltinType::Char16:
+ case clang::BuiltinType::Char32:
+ case clang::BuiltinType::UShort:
+ case clang::BuiltinType::UInt:
+ case clang::BuiltinType::ULong:
+ case clang::BuiltinType::ULongLong:
+ case clang::BuiltinType::UInt128:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::WChar_S:
+ case clang::BuiltinType::Short:
+ case clang::BuiltinType::Int:
+ case clang::BuiltinType::Long:
+ case clang::BuiltinType::LongLong:
+ case clang::BuiltinType::Int128:
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::LongDouble:
break;
- case BuiltinType::NullPtr:
+ case clang::BuiltinType::NullPtr:
return eLanguageTypeC_plus_plus;
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCSel:
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ case clang::BuiltinType::ObjCSel:
return eLanguageTypeObjC;
- case BuiltinType::Dependent:
- case BuiltinType::Overload:
- case BuiltinType::BoundMember:
- case BuiltinType::UnknownAny:
+ case clang::BuiltinType::Dependent:
+ case clang::BuiltinType::Overload:
+ case clang::BuiltinType::BoundMember:
+ case clang::BuiltinType::UnknownAny:
break;
}
break;
case clang::Type::Typedef:
- return ClangASTType(m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetMinimumLanguage();
+ return ClangASTType(m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetMinimumLanguage();
}
}
return lldb::eLanguageTypeC;
@@ -1414,7 +1518,7 @@ ClangASTType::GetTypeClass () const
if (!IsValid())
return lldb::eTypeClassInvalid;
- QualType qual_type(GetQualType());
+ clang::QualType qual_type(GetQualType());
switch (qual_type->getTypeClass())
{
@@ -1444,8 +1548,8 @@ ClangASTType::GetTypeClass () const
case clang::Type::ObjCInterface: return lldb::eTypeClassObjCInterface;
case clang::Type::Record:
{
- const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
- const RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
if (record_decl->isUnion())
return lldb::eTypeClassUnion;
else if (record_decl->isStruct())
@@ -1458,9 +1562,9 @@ ClangASTType::GetTypeClass () const
case clang::Type::Typedef: return lldb::eTypeClassTypedef;
case clang::Type::UnresolvedUsing: break;
case clang::Type::Paren:
- return ClangASTType(m_ast, cast<ParenType>(qual_type)->desugar()).GetTypeClass();
+ return ClangASTType(m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetTypeClass();
case clang::Type::Elaborated:
- return ClangASTType(m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetTypeClass();
+ return ClangASTType(m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetTypeClass();
case clang::Type::Attributed: break;
case clang::Type::TemplateTypeParm: break;
@@ -1480,6 +1584,7 @@ ClangASTType::GetTypeClass () const
// pointer type decayed from an array or function type.
case clang::Type::Decayed: break;
+ case clang::Type::Adjusted: break;
}
// We don't know hot to display this type...
return lldb::eTypeClassOther;
@@ -1510,7 +1615,7 @@ ClangASTType::AddConstModifier () const
{
if (m_type)
{
- QualType result(GetQualType());
+ clang::QualType result(GetQualType());
result.addConst();
return ClangASTType (m_ast, result);
}
@@ -1522,7 +1627,7 @@ ClangASTType::AddRestrictModifier () const
{
if (m_type)
{
- QualType result(GetQualType());
+ clang::QualType result(GetQualType());
result.getQualifiers().setRestrict (true);
return ClangASTType (m_ast, result);
}
@@ -1534,7 +1639,7 @@ ClangASTType::AddVolatileModifier () const
{
if (m_type)
{
- QualType result(GetQualType());
+ clang::QualType result(GetQualType());
result.getQualifiers().setVolatile (true);
return ClangASTType (m_ast, result);
}
@@ -1542,16 +1647,22 @@ ClangASTType::AddVolatileModifier () const
}
ClangASTType
-ClangASTType::GetArrayElementType (uint64_t& stride) const
+ClangASTType::GetArrayElementType (uint64_t *stride) const
{
if (IsValid())
{
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
+
+ const clang::Type *array_elem_type = qual_type.getTypePtr()->getArrayElementTypeNoTypeQual();
+
+ if (!array_elem_type)
+ return ClangASTType();
- ClangASTType element_type (m_ast, qual_type.getTypePtr()->getArrayElementTypeNoTypeQual()->getCanonicalTypeUnqualified());
+ ClangASTType element_type (m_ast, array_elem_type->getCanonicalTypeUnqualified());
// TODO: the real stride will be >= this value.. find the real one!
- stride = element_type.GetByteSize();
+ if (stride)
+ *stride = element_type.GetByteSize();
return element_type;
@@ -1567,8 +1678,8 @@ ClangASTType::GetCanonicalType () const
return ClangASTType();
}
-static QualType
-GetFullyUnqualifiedType_Impl (ASTContext *ast, QualType qual_type)
+static clang::QualType
+GetFullyUnqualifiedType_Impl (clang::ASTContext *ast, clang::QualType qual_type)
{
if (qual_type->isPointerType())
qual_type = ast->getPointerType(GetFullyUnqualifiedType_Impl(ast, qual_type->getPointeeType()));
@@ -1594,7 +1705,7 @@ ClangASTType::GetFunctionArgumentCount () const
{
if (IsValid())
{
- const FunctionProtoType* func = dyn_cast<FunctionProtoType>(GetCanonicalQualType());
+ const clang::FunctionProtoType* func = llvm::dyn_cast<clang::FunctionProtoType>(GetCanonicalQualType());
if (func)
return func->getNumParams();
}
@@ -1606,7 +1717,7 @@ ClangASTType::GetFunctionArgumentTypeAtIndex (size_t idx)
{
if (IsValid())
{
- const FunctionProtoType* func = dyn_cast<FunctionProtoType>(GetCanonicalQualType());
+ const clang::FunctionProtoType* func = llvm::dyn_cast<clang::FunctionProtoType>(GetCanonicalQualType());
if (func)
{
const uint32_t num_args = func->getNumParams();
@@ -1622,8 +1733,8 @@ ClangASTType::GetFunctionReturnType () const
{
if (IsValid())
{
- QualType qual_type(GetCanonicalQualType());
- const FunctionProtoType* func = dyn_cast<FunctionProtoType>(qual_type.getTypePtr());
+ clang::QualType qual_type(GetCanonicalQualType());
+ const clang::FunctionProtoType* func = llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr());
if (func)
return ClangASTType(m_ast, func->getReturnType());
}
@@ -1665,19 +1776,19 @@ ClangASTType::CreateTypedefType (const char *typedef_name,
{
if (IsValid() && typedef_name && typedef_name[0])
{
- QualType qual_type (GetQualType());
- if (decl_ctx == NULL)
+ clang::QualType qual_type (GetQualType());
+ if (decl_ctx == nullptr)
decl_ctx = m_ast->getTranslationUnitDecl();
- TypedefDecl *decl = TypedefDecl::Create (*m_ast,
- decl_ctx,
- SourceLocation(),
- SourceLocation(),
- &m_ast->Idents.get(typedef_name),
- m_ast->getTrivialTypeSourceInfo(qual_type));
+ clang::TypedefDecl *decl = clang::TypedefDecl::Create (*m_ast,
+ decl_ctx,
+ clang::SourceLocation(),
+ clang::SourceLocation(),
+ &m_ast->Idents.get(typedef_name),
+ m_ast->getTrivialTypeSourceInfo(qual_type));
- decl->setAccess(AS_public); // TODO respect proper access specifier
+ decl->setAccess(clang::AS_public); // TODO respect proper access specifier
- // Get a uniqued QualType for the typedef decl type
+ // Get a uniqued clang::QualType for the typedef decl type
return ClangASTType (m_ast, m_ast->getTypedefType (decl));
}
return ClangASTType();
@@ -1689,7 +1800,7 @@ ClangASTType::GetPointeeType () const
{
if (m_type)
{
- QualType qual_type(GetQualType());
+ clang::QualType qual_type(GetQualType());
return ClangASTType (m_ast, qual_type.getTypePtr()->getPointeeType());
}
return ClangASTType();
@@ -1700,7 +1811,7 @@ ClangASTType::GetPointerType () const
{
if (IsValid())
{
- QualType qual_type (GetQualType());
+ clang::QualType qual_type (GetQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
@@ -1721,7 +1832,7 @@ ClangASTType::GetTypedefedType () const
{
if (IsValid())
{
- const TypedefType *typedef_type = dyn_cast<TypedefType>(GetQualType());
+ const clang::TypedefType *typedef_type = llvm::dyn_cast<clang::TypedefType>(GetQualType());
if (typedef_type)
return ClangASTType (m_ast, typedef_type->getDecl()->getUnderlyingType());
}
@@ -1733,7 +1844,7 @@ ClangASTType::RemoveFastQualifiers () const
{
if (m_type)
{
- QualType qual_type(GetQualType());
+ clang::QualType qual_type(GetQualType());
qual_type.getQualifiers().removeFastQualifiers();
return ClangASTType (m_ast, qual_type);
}
@@ -1761,7 +1872,7 @@ ClangASTType::GetBitSize () const
{
if (GetCompleteType ())
{
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
const uint32_t bit_size = m_ast->getTypeSize (qual_type);
if (bit_size == 0)
{
@@ -1797,7 +1908,7 @@ ClangASTType::GetEncoding (uint64_t &count) const
return lldb::eEncodingInvalid;
count = 1;
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
switch (qual_type->getTypeClass())
{
@@ -1821,42 +1932,42 @@ ClangASTType::GetEncoding (uint64_t &count) const
break;
case clang::Type::Builtin:
- switch (cast<BuiltinType>(qual_type)->getKind())
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind())
{
default: assert(0 && "Unknown builtin type!");
- case BuiltinType::Void:
+ case clang::BuiltinType::Void:
break;
- case BuiltinType::Bool:
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- case BuiltinType::WChar_S:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::Short:
- case BuiltinType::Int:
- case BuiltinType::Long:
- case BuiltinType::LongLong:
- case BuiltinType::Int128: return lldb::eEncodingSint;
+ case clang::BuiltinType::Bool:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::WChar_S:
+ case clang::BuiltinType::Char16:
+ case clang::BuiltinType::Char32:
+ case clang::BuiltinType::Short:
+ case clang::BuiltinType::Int:
+ case clang::BuiltinType::Long:
+ case clang::BuiltinType::LongLong:
+ case clang::BuiltinType::Int128: return lldb::eEncodingSint;
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- case BuiltinType::WChar_U:
- case BuiltinType::UShort:
- case BuiltinType::UInt:
- case BuiltinType::ULong:
- case BuiltinType::ULongLong:
- case BuiltinType::UInt128: return lldb::eEncodingUint;
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::WChar_U:
+ case clang::BuiltinType::UShort:
+ case clang::BuiltinType::UInt:
+ case clang::BuiltinType::ULong:
+ case clang::BuiltinType::ULongLong:
+ case clang::BuiltinType::UInt128: return lldb::eEncodingUint;
- case BuiltinType::Float:
- case BuiltinType::Double:
- case BuiltinType::LongDouble: return lldb::eEncodingIEEE754;
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::LongDouble: return lldb::eEncodingIEEE754;
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCSel: return lldb::eEncodingUint;
+ case clang::BuiltinType::ObjCClass:
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCSel: return lldb::eEncodingUint;
- case BuiltinType::NullPtr: return lldb::eEncodingUint;
+ case clang::BuiltinType::NullPtr: return lldb::eEncodingUint;
}
break;
// All pointer types are represented as unsigned integer encodings.
@@ -1875,7 +1986,7 @@ ClangASTType::GetEncoding (uint64_t &count) const
encoding = lldb::eEncodingIEEE754;
else
{
- const ComplexType *complex_type = qual_type->getAsComplexIntegerType();
+ const clang::ComplexType *complex_type = qual_type->getAsComplexIntegerType();
if (complex_type)
encoding = ClangASTType(m_ast, complex_type->getElementType()).GetEncoding(count);
else
@@ -1889,13 +2000,13 @@ ClangASTType::GetEncoding (uint64_t &count) const
case clang::Type::Record: break;
case clang::Type::Enum: return lldb::eEncodingSint;
case clang::Type::Typedef:
- return ClangASTType(m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetEncoding(count);
+ return ClangASTType(m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetEncoding(count);
case clang::Type::Elaborated:
- return ClangASTType(m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetEncoding(count);
+ return ClangASTType(m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetEncoding(count);
case clang::Type::Paren:
- return ClangASTType(m_ast, cast<ParenType>(qual_type)->desugar()).GetEncoding(count);
+ return ClangASTType(m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetEncoding(count);
case clang::Type::DependentSizedArray:
case clang::Type::DependentSizedExtVector:
@@ -1916,6 +2027,7 @@ ClangASTType::GetEncoding (uint64_t &count) const
case clang::Type::Decltype:
case clang::Type::TemplateSpecialization:
case clang::Type::Atomic:
+ case clang::Type::Adjusted:
break;
// pointer type decayed from an array or function type.
@@ -1932,7 +2044,7 @@ ClangASTType::GetFormat () const
if (!IsValid())
return lldb::eFormatDefault;
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
switch (qual_type->getTypeClass())
{
@@ -1955,54 +2067,54 @@ ClangASTType::GetFormat () const
break;
case clang::Type::Builtin:
- switch (cast<BuiltinType>(qual_type)->getKind())
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind())
{
//default: assert(0 && "Unknown builtin type!");
- case BuiltinType::UnknownAny:
- case BuiltinType::Void:
- case BuiltinType::BoundMember:
+ case clang::BuiltinType::UnknownAny:
+ case clang::BuiltinType::Void:
+ case clang::BuiltinType::BoundMember:
break;
- case BuiltinType::Bool: return lldb::eFormatBoolean;
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- case BuiltinType::WChar_S:
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- case BuiltinType::WChar_U: return lldb::eFormatChar;
- case BuiltinType::Char16: return lldb::eFormatUnicode16;
- case BuiltinType::Char32: return lldb::eFormatUnicode32;
- case BuiltinType::UShort: return lldb::eFormatUnsigned;
- case BuiltinType::Short: return lldb::eFormatDecimal;
- case BuiltinType::UInt: return lldb::eFormatUnsigned;
- case BuiltinType::Int: return lldb::eFormatDecimal;
- case BuiltinType::ULong: return lldb::eFormatUnsigned;
- case BuiltinType::Long: return lldb::eFormatDecimal;
- case BuiltinType::ULongLong: return lldb::eFormatUnsigned;
- case BuiltinType::LongLong: return lldb::eFormatDecimal;
- case BuiltinType::UInt128: return lldb::eFormatUnsigned;
- case BuiltinType::Int128: return lldb::eFormatDecimal;
- case BuiltinType::Float: return lldb::eFormatFloat;
- case BuiltinType::Double: return lldb::eFormatFloat;
- case BuiltinType::LongDouble: return lldb::eFormatFloat;
- case BuiltinType::NullPtr:
- case BuiltinType::Overload:
- case BuiltinType::Dependent:
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCSel:
- case BuiltinType::Half:
- case BuiltinType::ARCUnbridgedCast:
- case BuiltinType::PseudoObject:
- case BuiltinType::BuiltinFn:
- case BuiltinType::OCLEvent:
- case BuiltinType::OCLImage1d:
- case BuiltinType::OCLImage1dArray:
- case BuiltinType::OCLImage1dBuffer:
- case BuiltinType::OCLImage2d:
- case BuiltinType::OCLImage2dArray:
- case BuiltinType::OCLImage3d:
- case BuiltinType::OCLSampler:
+ case clang::BuiltinType::Bool: return lldb::eFormatBoolean;
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::WChar_S:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::WChar_U: return lldb::eFormatChar;
+ case clang::BuiltinType::Char16: return lldb::eFormatUnicode16;
+ case clang::BuiltinType::Char32: return lldb::eFormatUnicode32;
+ case clang::BuiltinType::UShort: return lldb::eFormatUnsigned;
+ case clang::BuiltinType::Short: return lldb::eFormatDecimal;
+ case clang::BuiltinType::UInt: return lldb::eFormatUnsigned;
+ case clang::BuiltinType::Int: return lldb::eFormatDecimal;
+ case clang::BuiltinType::ULong: return lldb::eFormatUnsigned;
+ case clang::BuiltinType::Long: return lldb::eFormatDecimal;
+ case clang::BuiltinType::ULongLong: return lldb::eFormatUnsigned;
+ case clang::BuiltinType::LongLong: return lldb::eFormatDecimal;
+ case clang::BuiltinType::UInt128: return lldb::eFormatUnsigned;
+ case clang::BuiltinType::Int128: return lldb::eFormatDecimal;
+ case clang::BuiltinType::Float: return lldb::eFormatFloat;
+ case clang::BuiltinType::Double: return lldb::eFormatFloat;
+ case clang::BuiltinType::LongDouble: return lldb::eFormatFloat;
+ case clang::BuiltinType::NullPtr:
+ case clang::BuiltinType::Overload:
+ case clang::BuiltinType::Dependent:
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ case clang::BuiltinType::ObjCSel:
+ case clang::BuiltinType::Half:
+ case clang::BuiltinType::ARCUnbridgedCast:
+ case clang::BuiltinType::PseudoObject:
+ case clang::BuiltinType::BuiltinFn:
+ case clang::BuiltinType::OCLEvent:
+ case clang::BuiltinType::OCLImage1d:
+ case clang::BuiltinType::OCLImage1dArray:
+ case clang::BuiltinType::OCLImage1dBuffer:
+ case clang::BuiltinType::OCLImage2d:
+ case clang::BuiltinType::OCLImage2dArray:
+ case clang::BuiltinType::OCLImage3d:
+ case clang::BuiltinType::OCLSampler:
return lldb::eFormatHex;
}
break;
@@ -2023,13 +2135,13 @@ ClangASTType::GetFormat () const
case clang::Type::Record: break;
case clang::Type::Enum: return lldb::eFormatEnum;
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetFormat();
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetFormat();
case clang::Type::Auto:
- return ClangASTType (m_ast, cast<AutoType>(qual_type)->desugar()).GetFormat();
+ return ClangASTType (m_ast, llvm::cast<clang::AutoType>(qual_type)->desugar()).GetFormat();
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).GetFormat();
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetFormat();
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetFormat();
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetFormat();
case clang::Type::DependentSizedArray:
case clang::Type::DependentSizedExtVector:
case clang::Type::UnresolvedUsing:
@@ -2048,6 +2160,7 @@ ClangASTType::GetFormat () const
case clang::Type::Decltype:
case clang::Type::TemplateSpecialization:
case clang::Type::Atomic:
+ case clang::Type::Adjusted:
break;
// pointer type decayed from an array or function type.
@@ -2059,7 +2172,7 @@ ClangASTType::GetFormat () const
}
static bool
-ObjCDeclHasIVars (ObjCInterfaceDecl *class_interface_decl, bool check_superclass)
+ObjCDeclHasIVars (clang::ObjCInterfaceDecl *class_interface_decl, bool check_superclass)
{
while (class_interface_decl)
{
@@ -2081,15 +2194,15 @@ ClangASTType::GetNumChildren (bool omit_empty_base_classes) const
return 0;
uint32_t num_children = 0;
- QualType qual_type(GetQualType());
+ clang::QualType qual_type(GetQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Builtin:
- switch (cast<BuiltinType>(qual_type)->getKind())
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind())
{
- case BuiltinType::ObjCId: // child is Class
- case BuiltinType::ObjCClass: // child is Class
+ case clang::BuiltinType::ObjCId: // child is Class
+ case clang::BuiltinType::ObjCClass: // child is Class
num_children = 1;
break;
@@ -2103,10 +2216,10 @@ ClangASTType::GetNumChildren (bool omit_empty_base_classes) const
case clang::Type::Record:
if (GetCompleteQualType (m_ast, qual_type))
{
- const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
- const RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
assert(record_decl);
- const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
if (cxx_record_decl)
{
if (omit_empty_base_classes)
@@ -2115,12 +2228,12 @@ ClangASTType::GetNumChildren (bool omit_empty_base_classes) const
// base classes contain any fields. This can help
// limit the noise in variable views by not having to
// show base classes that contain no members.
- CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ clang::CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
base_class != base_class_end;
++base_class)
{
- const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+ const clang::CXXRecordDecl *base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl());
// Skip empty base classes
if (ClangASTContext::RecordHasFields(base_class_decl) == false)
@@ -2136,7 +2249,7 @@ ClangASTType::GetNumChildren (bool omit_empty_base_classes) const
}
}
- RecordDecl::field_iterator field, field_end;
+ clang::RecordDecl::field_iterator field, field_end;
for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field)
++num_children;
}
@@ -2146,16 +2259,16 @@ ClangASTType::GetNumChildren (bool omit_empty_base_classes) const
case clang::Type::ObjCInterface:
if (GetCompleteQualType (m_ast, qual_type))
{
- const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
assert (objc_class_type);
if (objc_class_type)
{
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
if (class_interface_decl)
{
- ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
+ clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
if (superclass_interface_decl)
{
if (omit_empty_base_classes)
@@ -2175,8 +2288,8 @@ ClangASTType::GetNumChildren (bool omit_empty_base_classes) const
case clang::Type::ObjCObjectPointer:
{
- const ObjCObjectPointerType *pointer_type = cast<ObjCObjectPointerType>(qual_type.getTypePtr());
- QualType pointee_type = pointer_type->getPointeeType();
+ const clang::ObjCObjectPointerType *pointer_type = llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr());
+ clang::QualType pointee_type = pointer_type->getPointeeType();
uint32_t num_pointee_children = ClangASTType (m_ast,pointee_type).GetNumChildren (omit_empty_base_classes);
// If this type points to a simple type, then it has 1 child
if (num_pointee_children == 0)
@@ -2188,17 +2301,17 @@ ClangASTType::GetNumChildren (bool omit_empty_base_classes) const
case clang::Type::Vector:
case clang::Type::ExtVector:
- num_children = cast<VectorType>(qual_type.getTypePtr())->getNumElements();
+ num_children = llvm::cast<clang::VectorType>(qual_type.getTypePtr())->getNumElements();
break;
case clang::Type::ConstantArray:
- num_children = cast<ConstantArrayType>(qual_type.getTypePtr())->getSize().getLimitedValue();
+ num_children = llvm::cast<clang::ConstantArrayType>(qual_type.getTypePtr())->getSize().getLimitedValue();
break;
case clang::Type::Pointer:
{
- const PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr());
- QualType pointee_type (pointer_type->getPointeeType());
+ const clang::PointerType *pointer_type = llvm::cast<clang::PointerType>(qual_type.getTypePtr());
+ clang::QualType pointee_type (pointer_type->getPointeeType());
uint32_t num_pointee_children = ClangASTType (m_ast,pointee_type).GetNumChildren (omit_empty_base_classes);
if (num_pointee_children == 0)
{
@@ -2214,8 +2327,8 @@ ClangASTType::GetNumChildren (bool omit_empty_base_classes) const
case clang::Type::LValueReference:
case clang::Type::RValueReference:
{
- const ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
- QualType pointee_type = reference_type->getPointeeType();
+ const clang::ReferenceType *reference_type = llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
+ clang::QualType pointee_type = reference_type->getPointeeType();
uint32_t num_pointee_children = ClangASTType (m_ast, pointee_type).GetNumChildren (omit_empty_base_classes);
// If this type points to a simple type, then it has 1 child
if (num_pointee_children == 0)
@@ -2227,15 +2340,15 @@ ClangASTType::GetNumChildren (bool omit_empty_base_classes) const
case clang::Type::Typedef:
- num_children = ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumChildren (omit_empty_base_classes);
+ num_children = ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumChildren (omit_empty_base_classes);
break;
case clang::Type::Elaborated:
- num_children = ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetNumChildren (omit_empty_base_classes);
+ num_children = ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetNumChildren (omit_empty_base_classes);
break;
case clang::Type::Paren:
- num_children = ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).GetNumChildren (omit_empty_base_classes);
+ num_children = ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetNumChildren (omit_empty_base_classes);
break;
default:
break;
@@ -2248,11 +2361,11 @@ ClangASTType::GetBasicTypeEnumeration () const
{
if (IsValid())
{
- QualType qual_type(GetQualType());
+ clang::QualType qual_type(GetQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
if (type_class == clang::Type::Builtin)
{
- switch (cast<clang::BuiltinType>(qual_type)->getKind())
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind())
{
case clang::BuiltinType::Void: return eBasicTypeVoid;
case clang::BuiltinType::Bool: return eBasicTypeBool;
@@ -2316,14 +2429,14 @@ ClangASTType::GetNumDirectBaseClasses () const
return 0;
uint32_t count = 0;
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Record:
if (GetCompleteType())
{
- const CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
if (cxx_record_decl)
count = cxx_record_decl->getNumBases();
}
@@ -2336,10 +2449,10 @@ ClangASTType::GetNumDirectBaseClasses () const
case clang::Type::ObjCObject:
if (GetCompleteType())
{
- const ObjCObjectType *objc_class_type = qual_type->getAsObjCQualifiedInterfaceType();
+ const clang::ObjCObjectType *objc_class_type = qual_type->getAsObjCQualifiedInterfaceType();
if (objc_class_type)
{
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
if (class_interface_decl && class_interface_decl->getSuperClass())
count = 1;
@@ -2349,10 +2462,10 @@ ClangASTType::GetNumDirectBaseClasses () const
case clang::Type::ObjCInterface:
if (GetCompleteType())
{
- const ObjCInterfaceType *objc_interface_type = qual_type->getAs<ObjCInterfaceType>();
+ const clang::ObjCInterfaceType *objc_interface_type = qual_type->getAs<clang::ObjCInterfaceType>();
if (objc_interface_type)
{
- ObjCInterfaceDecl *class_interface_decl = objc_interface_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_interface_type->getInterface();
if (class_interface_decl && class_interface_decl->getSuperClass())
count = 1;
@@ -2362,15 +2475,15 @@ ClangASTType::GetNumDirectBaseClasses () const
case clang::Type::Typedef:
- count = ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumDirectBaseClasses ();
+ count = ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumDirectBaseClasses ();
break;
case clang::Type::Elaborated:
- count = ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetNumDirectBaseClasses ();
+ count = ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetNumDirectBaseClasses ();
break;
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetNumDirectBaseClasses ();
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetNumDirectBaseClasses ();
default:
break;
@@ -2385,29 +2498,29 @@ ClangASTType::GetNumVirtualBaseClasses () const
return 0;
uint32_t count = 0;
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Record:
if (GetCompleteType())
{
- const CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
if (cxx_record_decl)
count = cxx_record_decl->getNumVBases();
}
break;
case clang::Type::Typedef:
- count = ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumVirtualBaseClasses();
+ count = ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumVirtualBaseClasses();
break;
case clang::Type::Elaborated:
- count = ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetNumVirtualBaseClasses();
+ count = ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetNumVirtualBaseClasses();
break;
case clang::Type::Paren:
- count = ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetNumVirtualBaseClasses();
+ count = ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetNumVirtualBaseClasses();
break;
default:
@@ -2423,21 +2536,21 @@ ClangASTType::GetNumFields () const
return 0;
uint32_t count = 0;
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Record:
if (GetCompleteType())
{
- const RecordType *record_type = dyn_cast<RecordType>(qual_type.getTypePtr());
+ const clang::RecordType *record_type = llvm::dyn_cast<clang::RecordType>(qual_type.getTypePtr());
if (record_type)
{
- RecordDecl *record_decl = record_type->getDecl();
+ clang::RecordDecl *record_decl = record_type->getDecl();
if (record_decl)
{
uint32_t field_idx = 0;
- RecordDecl::field_iterator field, field_end;
+ clang::RecordDecl::field_iterator field, field_end;
for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field)
++field_idx;
count = field_idx;
@@ -2447,24 +2560,24 @@ ClangASTType::GetNumFields () const
break;
case clang::Type::Typedef:
- count = ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumFields();
+ count = ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumFields();
break;
case clang::Type::Elaborated:
- count = ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetNumFields();
+ count = ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetNumFields();
break;
case clang::Type::Paren:
- count = ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetNumFields();
+ count = ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetNumFields();
break;
case clang::Type::ObjCObjectPointer:
if (GetCompleteType())
{
- const ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType();
+ const clang::ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType();
if (objc_class_type)
{
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl();
if (class_interface_decl)
count = class_interface_decl->ivar_size();
@@ -2476,10 +2589,10 @@ ClangASTType::GetNumFields () const
case clang::Type::ObjCInterface:
if (GetCompleteType())
{
- const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
if (objc_class_type)
{
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
if (class_interface_decl)
count = class_interface_decl->ivar_size();
@@ -2499,18 +2612,18 @@ ClangASTType::GetDirectBaseClassAtIndex (size_t idx, uint32_t *bit_offset_ptr) c
if (!IsValid())
return ClangASTType();
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Record:
if (GetCompleteType())
{
- const CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
if (cxx_record_decl)
{
uint32_t curr_idx = 0;
- CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ clang::CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
base_class != base_class_end;
++base_class, ++curr_idx)
@@ -2519,8 +2632,8 @@ ClangASTType::GetDirectBaseClassAtIndex (size_t idx, uint32_t *bit_offset_ptr) c
{
if (bit_offset_ptr)
{
- const ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(cxx_record_decl);
- const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+ const clang::ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(cxx_record_decl);
+ const clang::CXXRecordDecl *base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl());
if (base_class->isVirtual())
*bit_offset_ptr = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8;
else
@@ -2539,14 +2652,14 @@ ClangASTType::GetDirectBaseClassAtIndex (size_t idx, uint32_t *bit_offset_ptr) c
case clang::Type::ObjCObject:
if (idx == 0 && GetCompleteType())
{
- const ObjCObjectType *objc_class_type = qual_type->getAsObjCQualifiedInterfaceType();
+ const clang::ObjCObjectType *objc_class_type = qual_type->getAsObjCQualifiedInterfaceType();
if (objc_class_type)
{
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
if (class_interface_decl)
{
- ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
+ clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
if (superclass_interface_decl)
{
if (bit_offset_ptr)
@@ -2560,14 +2673,14 @@ ClangASTType::GetDirectBaseClassAtIndex (size_t idx, uint32_t *bit_offset_ptr) c
case clang::Type::ObjCInterface:
if (idx == 0 && GetCompleteType())
{
- const ObjCObjectType *objc_interface_type = qual_type->getAs<ObjCInterfaceType>();
+ const clang::ObjCObjectType *objc_interface_type = qual_type->getAs<clang::ObjCInterfaceType>();
if (objc_interface_type)
{
- ObjCInterfaceDecl *class_interface_decl = objc_interface_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_interface_type->getInterface();
if (class_interface_decl)
{
- ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
+ clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
if (superclass_interface_decl)
{
if (bit_offset_ptr)
@@ -2581,13 +2694,13 @@ ClangASTType::GetDirectBaseClassAtIndex (size_t idx, uint32_t *bit_offset_ptr) c
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetDirectBaseClassAtIndex (idx, bit_offset_ptr);
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetDirectBaseClassAtIndex (idx, bit_offset_ptr);
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetDirectBaseClassAtIndex (idx, bit_offset_ptr);
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetDirectBaseClassAtIndex (idx, bit_offset_ptr);
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetDirectBaseClassAtIndex (idx, bit_offset_ptr);
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetDirectBaseClassAtIndex (idx, bit_offset_ptr);
default:
break;
@@ -2601,18 +2714,18 @@ ClangASTType::GetVirtualBaseClassAtIndex (size_t idx, uint32_t *bit_offset_ptr)
if (!IsValid())
return ClangASTType();
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Record:
if (GetCompleteType())
{
- const CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
if (cxx_record_decl)
{
uint32_t curr_idx = 0;
- CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ clang::CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
for (base_class = cxx_record_decl->vbases_begin(), base_class_end = cxx_record_decl->vbases_end();
base_class != base_class_end;
++base_class, ++curr_idx)
@@ -2621,8 +2734,8 @@ ClangASTType::GetVirtualBaseClassAtIndex (size_t idx, uint32_t *bit_offset_ptr)
{
if (bit_offset_ptr)
{
- const ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(cxx_record_decl);
- const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+ const clang::ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(cxx_record_decl);
+ const clang::CXXRecordDecl *base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl());
*bit_offset_ptr = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8;
}
@@ -2634,13 +2747,13 @@ ClangASTType::GetVirtualBaseClassAtIndex (size_t idx, uint32_t *bit_offset_ptr)
break;
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetVirtualBaseClassAtIndex (idx, bit_offset_ptr);
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetVirtualBaseClassAtIndex (idx, bit_offset_ptr);
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetVirtualBaseClassAtIndex (idx, bit_offset_ptr);
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetVirtualBaseClassAtIndex (idx, bit_offset_ptr);
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetVirtualBaseClassAtIndex (idx, bit_offset_ptr);
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetVirtualBaseClassAtIndex (idx, bit_offset_ptr);
default:
break;
@@ -2650,7 +2763,7 @@ ClangASTType::GetVirtualBaseClassAtIndex (size_t idx, uint32_t *bit_offset_ptr)
static clang_type_t
GetObjCFieldAtIndex (clang::ASTContext *ast,
- ObjCInterfaceDecl *class_interface_decl,
+ clang::ObjCInterfaceDecl *class_interface_decl,
size_t idx,
std::string& name,
uint64_t *bit_offset_ptr,
@@ -2661,22 +2774,22 @@ GetObjCFieldAtIndex (clang::ASTContext *ast,
{
if (idx < (class_interface_decl->ivar_size()))
{
- ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
+ clang::ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
uint32_t ivar_idx = 0;
for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos, ++ivar_idx)
{
if (ivar_idx == idx)
{
- const ObjCIvarDecl* ivar_decl = *ivar_pos;
+ const clang::ObjCIvarDecl* ivar_decl = *ivar_pos;
- QualType ivar_qual_type(ivar_decl->getType());
+ clang::QualType ivar_qual_type(ivar_decl->getType());
name.assign(ivar_decl->getNameAsString());
if (bit_offset_ptr)
{
- const ASTRecordLayout &interface_layout = ast->getASTObjCInterfaceLayout(class_interface_decl);
+ const clang::ASTRecordLayout &interface_layout = ast->getASTObjCInterfaceLayout(class_interface_decl);
*bit_offset_ptr = interface_layout.getFieldOffset (ivar_idx);
}
@@ -2688,7 +2801,7 @@ GetObjCFieldAtIndex (clang::ASTContext *ast,
if (is_bitfield && ast)
{
- Expr *bitfield_bit_size_expr = ivar_pos->getBitWidth();
+ clang::Expr *bitfield_bit_size_expr = ivar_pos->getBitWidth();
llvm::APSInt bitfield_apsint;
if (bitfield_bit_size_expr && bitfield_bit_size_expr->EvaluateAsInt(bitfield_apsint, *ast))
{
@@ -2704,7 +2817,7 @@ GetObjCFieldAtIndex (clang::ASTContext *ast,
}
}
}
- return NULL;
+ return nullptr;
}
ClangASTType
@@ -2717,17 +2830,17 @@ ClangASTType::GetFieldAtIndex (size_t idx,
if (!IsValid())
return ClangASTType();
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Record:
if (GetCompleteType())
{
- const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
- const RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
uint32_t field_idx = 0;
- RecordDecl::field_iterator field, field_end;
+ clang::RecordDecl::field_iterator field, field_end;
for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx)
{
if (idx == field_idx)
@@ -2740,7 +2853,7 @@ ClangASTType::GetFieldAtIndex (size_t idx,
// alignment (field_type_info.second) from the AST context.
if (bit_offset_ptr)
{
- const ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(record_decl);
+ const clang::ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(record_decl);
*bit_offset_ptr = record_layout.getFieldOffset (field_idx);
}
@@ -2752,7 +2865,7 @@ ClangASTType::GetFieldAtIndex (size_t idx,
if (is_bitfield)
{
- Expr *bitfield_bit_size_expr = field->getBitWidth();
+ clang::Expr *bitfield_bit_size_expr = field->getBitWidth();
llvm::APSInt bitfield_apsint;
if (bitfield_bit_size_expr && bitfield_bit_size_expr->EvaluateAsInt(bitfield_apsint, *m_ast))
{
@@ -2772,10 +2885,10 @@ ClangASTType::GetFieldAtIndex (size_t idx,
case clang::Type::ObjCObjectPointer:
if (GetCompleteType())
{
- const ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType();
+ const clang::ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType();
if (objc_class_type)
{
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl();
return ClangASTType (m_ast, GetObjCFieldAtIndex(m_ast, class_interface_decl, idx, name, bit_offset_ptr, bitfield_bit_size_ptr, is_bitfield_ptr));
}
}
@@ -2785,11 +2898,11 @@ ClangASTType::GetFieldAtIndex (size_t idx,
case clang::Type::ObjCInterface:
if (GetCompleteType())
{
- const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
assert (objc_class_type);
if (objc_class_type)
{
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
return ClangASTType (m_ast, GetObjCFieldAtIndex(m_ast, class_interface_decl, idx, name, bit_offset_ptr, bitfield_bit_size_ptr, is_bitfield_ptr));
}
}
@@ -2797,7 +2910,7 @@ ClangASTType::GetFieldAtIndex (size_t idx,
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).
GetFieldAtIndex (idx,
name,
bit_offset_ptr,
@@ -2805,7 +2918,7 @@ ClangASTType::GetFieldAtIndex (size_t idx,
is_bitfield_ptr);
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).
GetFieldAtIndex (idx,
name,
bit_offset_ptr,
@@ -2813,7 +2926,7 @@ ClangASTType::GetFieldAtIndex (size_t idx,
is_bitfield_ptr);
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).
GetFieldAtIndex (idx,
name,
bit_offset_ptr,
@@ -2859,12 +2972,12 @@ ClangASTType::GetNumPointeeChildren () const
if (!IsValid())
return 0;
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Builtin:
- switch (cast<clang::BuiltinType>(qual_type)->getKind())
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind())
{
case clang::BuiltinType::UnknownAny:
case clang::BuiltinType::Void:
@@ -2930,9 +3043,9 @@ ClangASTType::GetNumPointeeChildren () const
case clang::Type::FunctionProto: return 0; // When we function pointers, they have no children...
case clang::Type::FunctionNoProto: return 0; // When we function pointers, they have no children...
case clang::Type::UnresolvedUsing: return 0;
- case clang::Type::Paren: return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetNumPointeeChildren ();
- case clang::Type::Typedef: return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumPointeeChildren ();
- case clang::Type::Elaborated: return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetNumPointeeChildren ();
+ case clang::Type::Paren: return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetNumPointeeChildren ();
+ case clang::Type::Typedef: return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumPointeeChildren ();
+ case clang::Type::Elaborated: return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetNumPointeeChildren ();
case clang::Type::TypeOfExpr: return 0;
case clang::Type::TypeOf: return 0;
case clang::Type::Decltype: return 0;
@@ -2956,7 +3069,6 @@ ClangASTType::GetNumPointeeChildren () const
ClangASTType
ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
- const char *parent_name,
size_t idx,
bool transparent_pointers,
bool omit_empty_base_classes,
@@ -2967,12 +3079,13 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
uint32_t &child_bitfield_bit_size,
uint32_t &child_bitfield_bit_offset,
bool &child_is_base_class,
- bool &child_is_deref_of_parent) const
+ bool &child_is_deref_of_parent,
+ ValueObject *valobj) const
{
if (!IsValid())
return ClangASTType();
- QualType parent_qual_type(GetCanonicalQualType());
+ clang::QualType parent_qual_type(GetCanonicalQualType());
const clang::Type::TypeClass parent_type_class = parent_qual_type->getTypeClass();
child_bitfield_bit_size = 0;
child_bitfield_bit_offset = 0;
@@ -2985,7 +3098,7 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
case clang::Type::Builtin:
if (idx_is_valid)
{
- switch (cast<clang::BuiltinType>(parent_qual_type)->getKind())
+ switch (llvm::cast<clang::BuiltinType>(parent_qual_type)->getKind())
{
case clang::BuiltinType::ObjCId:
case clang::BuiltinType::ObjCClass:
@@ -3002,39 +3115,106 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
case clang::Type::Record:
if (idx_is_valid && GetCompleteType())
{
- const RecordType *record_type = cast<RecordType>(parent_qual_type.getTypePtr());
- const RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordType *record_type = llvm::cast<clang::RecordType>(parent_qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
assert(record_decl);
- const ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(record_decl);
+ const clang::ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(record_decl);
uint32_t child_idx = 0;
- const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
if (cxx_record_decl)
{
// We might have base classes to print out first
- CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ clang::CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
base_class != base_class_end;
++base_class)
{
- const CXXRecordDecl *base_class_decl = NULL;
+ const clang::CXXRecordDecl *base_class_decl = nullptr;
// Skip empty base classes
if (omit_empty_base_classes)
{
- base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+ base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl());
if (ClangASTContext::RecordHasFields(base_class_decl) == false)
continue;
}
if (idx == child_idx)
{
- if (base_class_decl == NULL)
- base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+ if (base_class_decl == nullptr)
+ base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl());
if (base_class->isVirtual())
- bit_offset = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8;
+ {
+ bool handled = false;
+ if (valobj)
+ {
+ Error err;
+ AddressType addr_type = eAddressTypeInvalid;
+ lldb::addr_t vtable_ptr_addr = valobj->GetCPPVTableAddress(addr_type);
+
+ if (vtable_ptr_addr != LLDB_INVALID_ADDRESS && addr_type == eAddressTypeLoad)
+ {
+
+ ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ clang::VTableContextBase *vtable_ctx = m_ast->getVTableContext();
+ if (vtable_ctx)
+ {
+ if (vtable_ctx->isMicrosoft())
+ {
+ clang::MicrosoftVTableContext *msoft_vtable_ctx = static_cast<clang::MicrosoftVTableContext *>(vtable_ctx);
+
+ if (vtable_ptr_addr)
+ {
+ const lldb::addr_t vbtable_ptr_addr = vtable_ptr_addr + record_layout.getVBPtrOffset().getQuantity();
+
+ const lldb::addr_t vbtable_ptr = process->ReadPointerFromMemory(vbtable_ptr_addr, err);
+ if (vbtable_ptr != LLDB_INVALID_ADDRESS)
+ {
+ // Get the index into the virtual base table. The index is the index in uint32_t from vbtable_ptr
+ const unsigned vbtable_index = msoft_vtable_ctx->getVBTableIndex(cxx_record_decl, base_class_decl);
+ const lldb::addr_t base_offset_addr = vbtable_ptr + vbtable_index * 4;
+ const uint32_t base_offset = process->ReadUnsignedIntegerFromMemory(base_offset_addr, 4, UINT32_MAX, err);
+ if (base_offset != UINT32_MAX)
+ {
+ handled = true;
+ bit_offset = base_offset * 8;
+ }
+ }
+ }
+ }
+ else
+ {
+ clang::ItaniumVTableContext *itanium_vtable_ctx = static_cast<clang::ItaniumVTableContext *>(vtable_ctx);
+ if (vtable_ptr_addr)
+ {
+ const lldb::addr_t vtable_ptr = process->ReadPointerFromMemory(vtable_ptr_addr, err);
+ if (vtable_ptr != LLDB_INVALID_ADDRESS)
+ {
+ clang::CharUnits base_offset_offset = itanium_vtable_ctx->getVirtualBaseOffsetOffset(cxx_record_decl, base_class_decl);
+ const lldb::addr_t base_offset_addr = vtable_ptr + base_offset_offset.getQuantity();
+ const uint32_t base_offset = process->ReadUnsignedIntegerFromMemory(base_offset_addr, 4, UINT32_MAX, err);
+ if (base_offset != UINT32_MAX)
+ {
+ handled = true;
+ bit_offset = base_offset * 8;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+ if (!handled)
+ bit_offset = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8;
+ }
else
bit_offset = record_layout.getBaseClassOffset(base_class_decl).getQuantity() * 8;
@@ -3057,7 +3237,7 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
}
// Make sure index is in range...
uint32_t field_idx = 0;
- RecordDecl::field_iterator field, field_end;
+ clang::RecordDecl::field_iterator field, field_end;
for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx, ++child_idx)
{
if (idx == child_idx)
@@ -3088,18 +3268,18 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
case clang::Type::ObjCInterface:
if (idx_is_valid && GetCompleteType())
{
- const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(parent_qual_type.getTypePtr());
+ const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(parent_qual_type.getTypePtr());
assert (objc_class_type);
if (objc_class_type)
{
uint32_t child_idx = 0;
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
if (class_interface_decl)
{
- const ASTRecordLayout &interface_layout = m_ast->getASTObjCInterfaceLayout(class_interface_decl);
- ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
+ const clang::ASTRecordLayout &interface_layout = m_ast->getASTObjCInterfaceLayout(class_interface_decl);
+ clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
if (superclass_interface_decl)
{
if (omit_empty_base_classes)
@@ -3109,14 +3289,14 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
{
if (idx == 0)
{
- QualType ivar_qual_type(m_ast->getObjCInterfaceType(superclass_interface_decl));
+ clang::QualType ivar_qual_type(m_ast->getObjCInterfaceType(superclass_interface_decl));
child_name.assign(superclass_interface_decl->getNameAsString().c_str());
- std::pair<uint64_t, unsigned> ivar_type_info = m_ast->getTypeInfo(ivar_qual_type.getTypePtr());
+ clang::TypeInfo ivar_type_info = m_ast->getTypeInfo(ivar_qual_type.getTypePtr());
- child_byte_size = ivar_type_info.first / 8;
+ child_byte_size = ivar_type_info.Width / 8;
child_byte_offset = 0;
child_is_base_class = true;
@@ -3134,21 +3314,21 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
if (idx < (child_idx + class_interface_decl->ivar_size()))
{
- ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
+ clang::ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos)
{
if (child_idx == idx)
{
- ObjCIvarDecl* ivar_decl = *ivar_pos;
+ clang::ObjCIvarDecl* ivar_decl = *ivar_pos;
- QualType ivar_qual_type(ivar_decl->getType());
+ clang::QualType ivar_qual_type(ivar_decl->getType());
child_name.assign(ivar_decl->getNameAsString().c_str());
- std::pair<uint64_t, unsigned> ivar_type_info = m_ast->getTypeInfo(ivar_qual_type.getTypePtr());
+ clang::TypeInfo ivar_type_info = m_ast->getTypeInfo(ivar_qual_type.getTypePtr());
- child_byte_size = ivar_type_info.first / 8;
+ child_byte_size = ivar_type_info.Width / 8;
// Figure out the field offset within the current struct/union/class type
// For ObjC objects, we can't trust the bit offset we get from the Clang AST, since
@@ -3156,13 +3336,13 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
// the changing size of base classes that are newer than this class.
// So if we have a process around that we can ask about this object, do so.
child_byte_offset = LLDB_INVALID_IVAR_OFFSET;
- Process *process = NULL;
+ Process *process = nullptr;
if (exe_ctx)
process = exe_ctx->GetProcessPtr();
if (process)
{
ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime();
- if (objc_runtime != NULL)
+ if (objc_runtime != nullptr)
{
ClangASTType parent_ast_type (m_ast, parent_qual_type);
child_byte_offset = objc_runtime->GetByteOffsetForIvar (parent_ast_type, ivar_decl->getNameAsString().c_str());
@@ -3172,7 +3352,7 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
// Setting this to UINT32_MAX to make sure we don't compute it twice...
bit_offset = UINT32_MAX;
- if (child_byte_offset == LLDB_INVALID_IVAR_OFFSET)
+ if (child_byte_offset == static_cast<int32_t>(LLDB_INVALID_IVAR_OFFSET))
{
bit_offset = interface_layout.getFieldOffset (child_idx - superclass_idx);
child_byte_offset = bit_offset / 8;
@@ -3209,7 +3389,6 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
child_is_deref_of_parent = false;
bool tmp_child_is_deref_of_parent = false;
return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
- parent_name,
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -3220,11 +3399,13 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- tmp_child_is_deref_of_parent);
+ tmp_child_is_deref_of_parent,
+ valobj);
}
else
{
child_is_deref_of_parent = true;
+ const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL;
if (parent_name)
{
child_name.assign(1, '*');
@@ -3246,7 +3427,7 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
case clang::Type::ExtVector:
if (idx_is_valid)
{
- const VectorType *array = cast<VectorType>(parent_qual_type.getTypePtr());
+ const clang::VectorType *array = llvm::cast<clang::VectorType>(parent_qual_type.getTypePtr());
if (array)
{
ClangASTType element_type (m_ast, array->getElementType());
@@ -3267,7 +3448,7 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
case clang::Type::IncompleteArray:
if (ignore_array_bounds || idx_is_valid)
{
- const ArrayType *array = cast<ArrayType>(parent_qual_type.getTypePtr());
+ const clang::ArrayType *array = llvm::cast<clang::ArrayType>(parent_qual_type.getTypePtr());
if (array)
{
ClangASTType element_type (m_ast, array->getElementType());
@@ -3299,7 +3480,6 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
child_is_deref_of_parent = false;
bool tmp_child_is_deref_of_parent = false;
return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
- parent_name,
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -3310,12 +3490,14 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- tmp_child_is_deref_of_parent);
+ tmp_child_is_deref_of_parent,
+ valobj);
}
else
{
child_is_deref_of_parent = true;
+ const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL;
if (parent_name)
{
child_name.assign(1, '*');
@@ -3337,14 +3519,13 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
case clang::Type::RValueReference:
if (idx_is_valid)
{
- const ReferenceType *reference_type = cast<ReferenceType>(parent_qual_type.getTypePtr());
+ const clang::ReferenceType *reference_type = llvm::cast<clang::ReferenceType>(parent_qual_type.getTypePtr());
ClangASTType pointee_clang_type (m_ast, reference_type->getPointeeType());
if (transparent_pointers && pointee_clang_type.IsAggregateType ())
{
child_is_deref_of_parent = false;
bool tmp_child_is_deref_of_parent = false;
return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
- parent_name,
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -3355,10 +3536,12 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- tmp_child_is_deref_of_parent);
+ tmp_child_is_deref_of_parent,
+ valobj);
}
else
{
+ const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL;
if (parent_name)
{
child_name.assign(1, '&');
@@ -3378,9 +3561,8 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
case clang::Type::Typedef:
{
- ClangASTType typedefed_clang_type (m_ast, cast<TypedefType>(parent_qual_type)->getDecl()->getUnderlyingType());
+ ClangASTType typedefed_clang_type (m_ast, llvm::cast<clang::TypedefType>(parent_qual_type)->getDecl()->getUnderlyingType());
return typedefed_clang_type.GetChildClangTypeAtIndex (exe_ctx,
- parent_name,
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -3391,15 +3573,15 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- child_is_deref_of_parent);
+ child_is_deref_of_parent,
+ valobj);
}
break;
case clang::Type::Elaborated:
{
- ClangASTType elaborated_clang_type (m_ast, cast<ElaboratedType>(parent_qual_type)->getNamedType());
+ ClangASTType elaborated_clang_type (m_ast, llvm::cast<clang::ElaboratedType>(parent_qual_type)->getNamedType());
return elaborated_clang_type.GetChildClangTypeAtIndex (exe_ctx,
- parent_name,
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -3410,14 +3592,14 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- child_is_deref_of_parent);
+ child_is_deref_of_parent,
+ valobj);
}
case clang::Type::Paren:
{
ClangASTType paren_clang_type (m_ast, llvm::cast<clang::ParenType>(parent_qual_type)->desugar());
return paren_clang_type.GetChildClangTypeAtIndex (exe_ctx,
- parent_name,
idx,
transparent_pointers,
omit_empty_base_classes,
@@ -3428,7 +3610,8 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
child_bitfield_bit_size,
child_bitfield_bit_offset,
child_is_base_class,
- child_is_deref_of_parent);
+ child_is_deref_of_parent,
+ valobj);
}
@@ -3439,7 +3622,7 @@ ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
}
static inline bool
-BaseSpecifierIsEmpty (const CXXBaseSpecifier *b)
+BaseSpecifierIsEmpty (const clang::CXXBaseSpecifier *b)
{
return ClangASTContext::RecordHasFields(b->getType()->getAsCXXRecordDecl()) == false;
}
@@ -3447,22 +3630,22 @@ BaseSpecifierIsEmpty (const CXXBaseSpecifier *b)
static uint32_t
GetIndexForRecordBase
(
- const RecordDecl *record_decl,
- const CXXBaseSpecifier *base_spec,
+ const clang::RecordDecl *record_decl,
+ const clang::CXXBaseSpecifier *base_spec,
bool omit_empty_base_classes
)
{
uint32_t child_idx = 0;
- const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
// const char *super_name = record_decl->getNameAsCString();
- // const char *base_name = base_spec->getType()->getAs<RecordType>()->getDecl()->getNameAsCString();
+ // const char *base_name = base_spec->getType()->getAs<clang::RecordType>()->getDecl()->getNameAsCString();
// printf ("GetIndexForRecordChild (%s, %s)\n", super_name, base_name);
//
if (cxx_record_decl)
{
- CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ clang::CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
base_class != base_class_end;
++base_class)
@@ -3475,7 +3658,7 @@ GetIndexForRecordBase
// printf ("GetIndexForRecordChild (%s, %s) base[%u] = %s\n", super_name, base_name,
// child_idx,
- // base_class->getType()->getAs<RecordType>()->getDecl()->getNameAsCString());
+ // base_class->getType()->getAs<clang::RecordType>()->getDecl()->getNameAsCString());
//
//
if (base_class == base_spec)
@@ -3489,14 +3672,14 @@ GetIndexForRecordBase
static uint32_t
-GetIndexForRecordChild (const RecordDecl *record_decl,
- NamedDecl *canonical_decl,
+GetIndexForRecordChild (const clang::RecordDecl *record_decl,
+ clang::NamedDecl *canonical_decl,
bool omit_empty_base_classes)
{
- uint32_t child_idx = ClangASTContext::GetNumBaseClasses (dyn_cast<CXXRecordDecl>(record_decl),
+ uint32_t child_idx = ClangASTContext::GetNumBaseClasses (llvm::dyn_cast<clang::CXXRecordDecl>(record_decl),
omit_empty_base_classes);
- RecordDecl::field_iterator field, field_end;
+ clang::RecordDecl::field_iterator field, field_end;
for (field = record_decl->field_begin(), field_end = record_decl->field_end();
field != field_end;
++field, ++child_idx)
@@ -3549,24 +3732,24 @@ ClangASTType::GetIndexOfChildMemberWithName (const char *name,
{
if (IsValid() && name && name[0])
{
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Record:
if (GetCompleteType ())
{
- const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
- const RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
assert(record_decl);
uint32_t child_idx = 0;
- const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
// Try and find a field that matches NAME
- RecordDecl::field_iterator field, field_end;
- StringRef name_sref(name);
+ clang::RecordDecl::field_iterator field, field_end;
+ llvm::StringRef name_sref(name);
for (field = record_decl->field_begin(), field_end = record_decl->field_end();
field != field_end;
++field, ++child_idx)
@@ -3591,27 +3774,27 @@ ClangASTType::GetIndexOfChildMemberWithName (const char *name,
if (cxx_record_decl)
{
- const RecordDecl *parent_record_decl = cxx_record_decl;
+ const clang::RecordDecl *parent_record_decl = cxx_record_decl;
//printf ("parent = %s\n", parent_record_decl->getNameAsCString());
//const Decl *root_cdecl = cxx_record_decl->getCanonicalDecl();
// Didn't find things easily, lets let clang do its thang...
- IdentifierInfo & ident_ref = m_ast->Idents.get(name_sref);
- DeclarationName decl_name(&ident_ref);
+ clang::IdentifierInfo & ident_ref = m_ast->Idents.get(name_sref);
+ clang::DeclarationName decl_name(&ident_ref);
- CXXBasePaths paths;
- if (cxx_record_decl->lookupInBases(CXXRecordDecl::FindOrdinaryMember,
+ clang::CXXBasePaths paths;
+ if (cxx_record_decl->lookupInBases(clang::CXXRecordDecl::FindOrdinaryMember,
decl_name.getAsOpaquePtr(),
paths))
{
- CXXBasePaths::const_paths_iterator path, path_end = paths.end();
+ clang::CXXBasePaths::const_paths_iterator path, path_end = paths.end();
for (path = paths.begin(); path != path_end; ++path)
{
const size_t num_path_elements = path->size();
for (size_t e=0; e<num_path_elements; ++e)
{
- CXXBasePathElement elem = (*path)[e];
+ clang::CXXBasePathElement elem = (*path)[e];
child_idx = GetIndexForRecordBase (parent_record_decl, elem.Base, omit_empty_base_classes);
if (child_idx == UINT32_MAX)
@@ -3622,10 +3805,10 @@ ClangASTType::GetIndexOfChildMemberWithName (const char *name,
else
{
child_indexes.push_back (child_idx);
- parent_record_decl = cast<RecordDecl>(elem.Base->getType()->getAs<RecordType>()->getDecl());
+ parent_record_decl = llvm::cast<clang::RecordDecl>(elem.Base->getType()->getAs<clang::RecordType>()->getDecl());
}
}
- for (NamedDecl *path_decl : path->Decls)
+ for (clang::NamedDecl *path_decl : path->Decls)
{
child_idx = GetIndexForRecordChild (parent_record_decl, path_decl, omit_empty_base_classes);
if (child_idx == UINT32_MAX)
@@ -3650,22 +3833,22 @@ ClangASTType::GetIndexOfChildMemberWithName (const char *name,
case clang::Type::ObjCInterface:
if (GetCompleteType ())
{
- StringRef name_sref(name);
- const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ llvm::StringRef name_sref(name);
+ const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
assert (objc_class_type);
if (objc_class_type)
{
uint32_t child_idx = 0;
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
if (class_interface_decl)
{
- ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
- ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
+ clang::ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
+ clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos, ++child_idx)
{
- const ObjCIvarDecl* ivar_decl = *ivar_pos;
+ const clang::ObjCIvarDecl* ivar_decl = *ivar_pos;
if (ivar_decl->getName().equals (name_sref))
{
@@ -3707,7 +3890,7 @@ ClangASTType::GetIndexOfChildMemberWithName (const char *name,
case clang::Type::ObjCObjectPointer:
{
- ClangASTType objc_object_clang_type (m_ast, cast<ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType());
+ ClangASTType objc_object_clang_type (m_ast, llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType());
return objc_object_clang_type.GetIndexOfChildMemberWithName (name,
omit_empty_base_classes,
child_indexes);
@@ -3717,7 +3900,7 @@ ClangASTType::GetIndexOfChildMemberWithName (const char *name,
case clang::Type::ConstantArray:
{
- // const ConstantArrayType *array = cast<ConstantArrayType>(parent_qual_type.getTypePtr());
+ // const clang::ConstantArrayType *array = llvm::cast<clang::ConstantArrayType>(parent_qual_type.getTypePtr());
// const uint64_t element_count = array->getSize().getLimitedValue();
//
// if (idx < element_count)
@@ -3738,8 +3921,8 @@ ClangASTType::GetIndexOfChildMemberWithName (const char *name,
// case clang::Type::MemberPointerType:
// {
- // MemberPointerType *mem_ptr_type = cast<MemberPointerType>(qual_type.getTypePtr());
- // QualType pointee_type = mem_ptr_type->getPointeeType();
+ // MemberPointerType *mem_ptr_type = llvm::cast<MemberPointerType>(qual_type.getTypePtr());
+ // clang::QualType pointee_type = mem_ptr_type->getPointeeType();
//
// if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
// {
@@ -3753,8 +3936,8 @@ ClangASTType::GetIndexOfChildMemberWithName (const char *name,
case clang::Type::LValueReference:
case clang::Type::RValueReference:
{
- const ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
- QualType pointee_type(reference_type->getPointeeType());
+ const clang::ReferenceType *reference_type = llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
+ clang::QualType pointee_type(reference_type->getPointeeType());
ClangASTType pointee_clang_type (m_ast, pointee_type);
if (pointee_clang_type.IsAggregateType ())
@@ -3780,17 +3963,17 @@ ClangASTType::GetIndexOfChildMemberWithName (const char *name,
break;
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetIndexOfChildMemberWithName (name,
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetIndexOfChildMemberWithName (name,
omit_empty_base_classes,
child_indexes);
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetIndexOfChildMemberWithName (name,
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetIndexOfChildMemberWithName (name,
omit_empty_base_classes,
child_indexes);
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetIndexOfChildMemberWithName (name,
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetIndexOfChildMemberWithName (name,
omit_empty_base_classes,
child_indexes);
@@ -3811,7 +3994,7 @@ ClangASTType::GetIndexOfChildWithName (const char *name, bool omit_empty_base_cl
{
if (IsValid() && name && name[0])
{
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
@@ -3820,23 +4003,23 @@ ClangASTType::GetIndexOfChildWithName (const char *name, bool omit_empty_base_cl
case clang::Type::Record:
if (GetCompleteType ())
{
- const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
- const RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
assert(record_decl);
uint32_t child_idx = 0;
- const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
if (cxx_record_decl)
{
- CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ clang::CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
base_class != base_class_end;
++base_class)
{
// Skip empty base classes
- CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+ clang::CXXRecordDecl *base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl());
if (omit_empty_base_classes && ClangASTContext::RecordHasFields(base_class_decl) == false)
continue;
@@ -3849,8 +4032,8 @@ ClangASTType::GetIndexOfChildWithName (const char *name, bool omit_empty_base_cl
}
// Try and find a field that matches NAME
- RecordDecl::field_iterator field, field_end;
- StringRef name_sref(name);
+ clang::RecordDecl::field_iterator field, field_end;
+ llvm::StringRef name_sref(name);
for (field = record_decl->field_begin(), field_end = record_decl->field_end();
field != field_end;
++field, ++child_idx)
@@ -3866,22 +4049,22 @@ ClangASTType::GetIndexOfChildWithName (const char *name, bool omit_empty_base_cl
case clang::Type::ObjCInterface:
if (GetCompleteType())
{
- StringRef name_sref(name);
- const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ llvm::StringRef name_sref(name);
+ const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
assert (objc_class_type);
if (objc_class_type)
{
uint32_t child_idx = 0;
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
if (class_interface_decl)
{
- ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
- ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
+ clang::ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
+ clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos, ++child_idx)
{
- const ObjCIvarDecl* ivar_decl = *ivar_pos;
+ const clang::ObjCIvarDecl* ivar_decl = *ivar_pos;
if (ivar_decl->getName().equals (name_sref))
{
@@ -3905,14 +4088,14 @@ ClangASTType::GetIndexOfChildWithName (const char *name, bool omit_empty_base_cl
case clang::Type::ObjCObjectPointer:
{
- ClangASTType pointee_clang_type (m_ast, cast<ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType());
+ ClangASTType pointee_clang_type (m_ast, llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType());
return pointee_clang_type.GetIndexOfChildWithName (name, omit_empty_base_classes);
}
break;
case clang::Type::ConstantArray:
{
- // const ConstantArrayType *array = cast<ConstantArrayType>(parent_qual_type.getTypePtr());
+ // const clang::ConstantArrayType *array = llvm::cast<clang::ConstantArrayType>(parent_qual_type.getTypePtr());
// const uint64_t element_count = array->getSize().getLimitedValue();
//
// if (idx < element_count)
@@ -3933,8 +4116,8 @@ ClangASTType::GetIndexOfChildWithName (const char *name, bool omit_empty_base_cl
// case clang::Type::MemberPointerType:
// {
- // MemberPointerType *mem_ptr_type = cast<MemberPointerType>(qual_type.getTypePtr());
- // QualType pointee_type = mem_ptr_type->getPointeeType();
+ // MemberPointerType *mem_ptr_type = llvm::cast<MemberPointerType>(qual_type.getTypePtr());
+ // clang::QualType pointee_type = mem_ptr_type->getPointeeType();
//
// if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
// {
@@ -3948,7 +4131,7 @@ ClangASTType::GetIndexOfChildWithName (const char *name, bool omit_empty_base_cl
case clang::Type::LValueReference:
case clang::Type::RValueReference:
{
- const ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
+ const clang::ReferenceType *reference_type = llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
ClangASTType pointee_type (m_ast, reference_type->getPointeeType());
if (pointee_type.IsAggregateType ())
@@ -3960,7 +4143,7 @@ ClangASTType::GetIndexOfChildWithName (const char *name, bool omit_empty_base_cl
case clang::Type::Pointer:
{
- const PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr());
+ const clang::PointerType *pointer_type = llvm::cast<clang::PointerType>(qual_type.getTypePtr());
ClangASTType pointee_type (m_ast, pointer_type->getPointeeType());
if (pointee_type.IsAggregateType ())
@@ -3989,13 +4172,13 @@ ClangASTType::GetIndexOfChildWithName (const char *name, bool omit_empty_base_cl
break;
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetIndexOfChildWithName (name, omit_empty_base_classes);
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetIndexOfChildWithName (name, omit_empty_base_classes);
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetIndexOfChildWithName (name, omit_empty_base_classes);
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetIndexOfChildWithName (name, omit_empty_base_classes);
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetIndexOfChildWithName (name, omit_empty_base_classes);
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetIndexOfChildWithName (name, omit_empty_base_classes);
default:
break;
@@ -4010,7 +4193,7 @@ ClangASTType::GetNumTemplateArguments () const
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
@@ -4018,10 +4201,10 @@ ClangASTType::GetNumTemplateArguments () const
case clang::Type::Record:
if (GetCompleteType ())
{
- const CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
if (cxx_record_decl)
{
- const ClassTemplateSpecializationDecl *template_decl = dyn_cast<ClassTemplateSpecializationDecl>(cxx_record_decl);
+ const clang::ClassTemplateSpecializationDecl *template_decl = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(cxx_record_decl);
if (template_decl)
return template_decl->getTemplateArgs().size();
}
@@ -4029,13 +4212,13 @@ ClangASTType::GetNumTemplateArguments () const
break;
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumTemplateArguments();
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumTemplateArguments();
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetNumTemplateArguments();
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetNumTemplateArguments();
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).GetNumTemplateArguments();
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetNumTemplateArguments();
default:
break;
@@ -4049,7 +4232,7 @@ ClangASTType::GetTemplateArgument (size_t arg_idx, lldb::TemplateArgumentKind &k
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
@@ -4057,13 +4240,13 @@ ClangASTType::GetTemplateArgument (size_t arg_idx, lldb::TemplateArgumentKind &k
case clang::Type::Record:
if (GetCompleteType ())
{
- const CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
if (cxx_record_decl)
{
- const ClassTemplateSpecializationDecl *template_decl = dyn_cast<ClassTemplateSpecializationDecl>(cxx_record_decl);
+ const clang::ClassTemplateSpecializationDecl *template_decl = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(cxx_record_decl);
if (template_decl && arg_idx < template_decl->getTemplateArgs().size())
{
- const TemplateArgument &template_arg = template_decl->getTemplateArgs()[arg_idx];
+ const clang::TemplateArgument &template_arg = template_decl->getTemplateArgs()[arg_idx];
switch (template_arg.getKind())
{
case clang::TemplateArgument::Null:
@@ -4099,7 +4282,7 @@ ClangASTType::GetTemplateArgument (size_t arg_idx, lldb::TemplateArgumentKind &k
return ClangASTType();
default:
- assert (!"Unhandled TemplateArgument::ArgKind");
+ assert (!"Unhandled clang::TemplateArgument::ArgKind");
break;
}
}
@@ -4108,13 +4291,13 @@ ClangASTType::GetTemplateArgument (size_t arg_idx, lldb::TemplateArgumentKind &k
break;
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetTemplateArgument (arg_idx, kind);
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetTemplateArgument (arg_idx, kind);
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetTemplateArgument (arg_idx, kind);
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetTemplateArgument (arg_idx, kind);
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).GetTemplateArgument (arg_idx, kind);
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetTemplateArgument (arg_idx, kind);
default:
break;
@@ -4125,15 +4308,15 @@ ClangASTType::GetTemplateArgument (size_t arg_idx, lldb::TemplateArgumentKind &k
}
static bool
-IsOperator (const char *name, OverloadedOperatorKind &op_kind)
+IsOperator (const char *name, clang::OverloadedOperatorKind &op_kind)
{
- if (name == NULL || name[0] == '\0')
+ if (name == nullptr || name[0] == '\0')
return false;
#define OPERATOR_PREFIX "operator"
#define OPERATOR_PREFIX_LENGTH (sizeof (OPERATOR_PREFIX) - 1)
- const char *post_op_name = NULL;
+ const char *post_op_name = nullptr;
bool no_space = true;
@@ -4153,7 +4336,7 @@ IsOperator (const char *name, OverloadedOperatorKind &op_kind)
// This is an operator, set the overloaded operator kind to invalid
// in case this is a conversion operator...
- op_kind = NUM_OVERLOADED_OPERATORS;
+ op_kind = clang::NUM_OVERLOADED_OPERATORS;
switch (post_op_name[0])
{
@@ -4165,204 +4348,197 @@ IsOperator (const char *name, OverloadedOperatorKind &op_kind)
if (no_space)
return false;
if (strcmp (post_op_name, "new") == 0)
- op_kind = OO_New;
+ op_kind = clang::OO_New;
else if (strcmp (post_op_name, "new[]") == 0)
- op_kind = OO_Array_New;
+ op_kind = clang::OO_Array_New;
break;
case 'd':
if (no_space)
return false;
if (strcmp (post_op_name, "delete") == 0)
- op_kind = OO_Delete;
+ op_kind = clang::OO_Delete;
else if (strcmp (post_op_name, "delete[]") == 0)
- op_kind = OO_Array_Delete;
+ op_kind = clang::OO_Array_Delete;
break;
case '+':
if (post_op_name[1] == '\0')
- op_kind = OO_Plus;
+ op_kind = clang::OO_Plus;
else if (post_op_name[2] == '\0')
{
if (post_op_name[1] == '=')
- op_kind = OO_PlusEqual;
+ op_kind = clang::OO_PlusEqual;
else if (post_op_name[1] == '+')
- op_kind = OO_PlusPlus;
+ op_kind = clang::OO_PlusPlus;
}
break;
case '-':
if (post_op_name[1] == '\0')
- op_kind = OO_Minus;
+ op_kind = clang::OO_Minus;
else if (post_op_name[2] == '\0')
{
switch (post_op_name[1])
{
- case '=': op_kind = OO_MinusEqual; break;
- case '-': op_kind = OO_MinusMinus; break;
- case '>': op_kind = OO_Arrow; break;
+ case '=': op_kind = clang::OO_MinusEqual; break;
+ case '-': op_kind = clang::OO_MinusMinus; break;
+ case '>': op_kind = clang::OO_Arrow; break;
}
}
else if (post_op_name[3] == '\0')
{
if (post_op_name[2] == '*')
- op_kind = OO_ArrowStar; break;
+ op_kind = clang::OO_ArrowStar; break;
}
break;
case '*':
if (post_op_name[1] == '\0')
- op_kind = OO_Star;
+ op_kind = clang::OO_Star;
else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
- op_kind = OO_StarEqual;
+ op_kind = clang::OO_StarEqual;
break;
case '/':
if (post_op_name[1] == '\0')
- op_kind = OO_Slash;
+ op_kind = clang::OO_Slash;
else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
- op_kind = OO_SlashEqual;
+ op_kind = clang::OO_SlashEqual;
break;
case '%':
if (post_op_name[1] == '\0')
- op_kind = OO_Percent;
+ op_kind = clang::OO_Percent;
else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
- op_kind = OO_PercentEqual;
+ op_kind = clang::OO_PercentEqual;
break;
case '^':
if (post_op_name[1] == '\0')
- op_kind = OO_Caret;
+ op_kind = clang::OO_Caret;
else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
- op_kind = OO_CaretEqual;
+ op_kind = clang::OO_CaretEqual;
break;
case '&':
if (post_op_name[1] == '\0')
- op_kind = OO_Amp;
+ op_kind = clang::OO_Amp;
else if (post_op_name[2] == '\0')
{
switch (post_op_name[1])
{
- case '=': op_kind = OO_AmpEqual; break;
- case '&': op_kind = OO_AmpAmp; break;
+ case '=': op_kind = clang::OO_AmpEqual; break;
+ case '&': op_kind = clang::OO_AmpAmp; break;
}
}
break;
case '|':
if (post_op_name[1] == '\0')
- op_kind = OO_Pipe;
+ op_kind = clang::OO_Pipe;
else if (post_op_name[2] == '\0')
{
switch (post_op_name[1])
{
- case '=': op_kind = OO_PipeEqual; break;
- case '|': op_kind = OO_PipePipe; break;
+ case '=': op_kind = clang::OO_PipeEqual; break;
+ case '|': op_kind = clang::OO_PipePipe; break;
}
}
break;
case '~':
if (post_op_name[1] == '\0')
- op_kind = OO_Tilde;
+ op_kind = clang::OO_Tilde;
break;
case '!':
if (post_op_name[1] == '\0')
- op_kind = OO_Exclaim;
+ op_kind = clang::OO_Exclaim;
else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
- op_kind = OO_ExclaimEqual;
+ op_kind = clang::OO_ExclaimEqual;
break;
case '=':
if (post_op_name[1] == '\0')
- op_kind = OO_Equal;
+ op_kind = clang::OO_Equal;
else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
- op_kind = OO_EqualEqual;
+ op_kind = clang::OO_EqualEqual;
break;
case '<':
if (post_op_name[1] == '\0')
- op_kind = OO_Less;
+ op_kind = clang::OO_Less;
else if (post_op_name[2] == '\0')
{
switch (post_op_name[1])
{
- case '<': op_kind = OO_LessLess; break;
- case '=': op_kind = OO_LessEqual; break;
+ case '<': op_kind = clang::OO_LessLess; break;
+ case '=': op_kind = clang::OO_LessEqual; break;
}
}
else if (post_op_name[3] == '\0')
{
if (post_op_name[2] == '=')
- op_kind = OO_LessLessEqual;
+ op_kind = clang::OO_LessLessEqual;
}
break;
case '>':
if (post_op_name[1] == '\0')
- op_kind = OO_Greater;
+ op_kind = clang::OO_Greater;
else if (post_op_name[2] == '\0')
{
switch (post_op_name[1])
{
- case '>': op_kind = OO_GreaterGreater; break;
- case '=': op_kind = OO_GreaterEqual; break;
+ case '>': op_kind = clang::OO_GreaterGreater; break;
+ case '=': op_kind = clang::OO_GreaterEqual; break;
}
}
else if (post_op_name[1] == '>' &&
post_op_name[2] == '=' &&
post_op_name[3] == '\0')
{
- op_kind = OO_GreaterGreaterEqual;
+ op_kind = clang::OO_GreaterGreaterEqual;
}
break;
case ',':
if (post_op_name[1] == '\0')
- op_kind = OO_Comma;
+ op_kind = clang::OO_Comma;
break;
case '(':
if (post_op_name[1] == ')' && post_op_name[2] == '\0')
- op_kind = OO_Call;
+ op_kind = clang::OO_Call;
break;
case '[':
if (post_op_name[1] == ']' && post_op_name[2] == '\0')
- op_kind = OO_Subscript;
+ op_kind = clang::OO_Subscript;
break;
}
return true;
}
-static inline bool
-check_op_param (uint32_t op_kind, bool unary, bool binary, uint32_t num_params)
+clang::EnumDecl *
+ClangASTType::GetAsEnumDecl () const
{
- // Special-case call since it can take any number of operands
- if(op_kind == OO_Call)
- return true;
-
- // The parameter count doens't include "this"
- if (num_params == 0)
- return unary;
- if (num_params == 1)
- return binary;
- else
- return false;
+ const clang::EnumType *enum_type = llvm::dyn_cast<clang::EnumType>(GetCanonicalQualType());
+ if (enum_type)
+ return enum_type->getDecl();
+ return NULL;
}
clang::RecordDecl *
ClangASTType::GetAsRecordDecl () const
{
- const RecordType *record_type = dyn_cast<RecordType>(GetCanonicalQualType());
+ const clang::RecordType *record_type = llvm::dyn_cast<clang::RecordType>(GetCanonicalQualType());
if (record_type)
return record_type->getDecl();
- return NULL;
+ return nullptr;
}
clang::CXXRecordDecl *
@@ -4371,13 +4547,13 @@ ClangASTType::GetAsCXXRecordDecl () const
return GetCanonicalQualType()->getAsCXXRecordDecl();
}
-ObjCInterfaceDecl *
+clang::ObjCInterfaceDecl *
ClangASTType::GetAsObjCInterfaceDecl () const
{
- const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(GetCanonicalQualType());
+ const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(GetCanonicalQualType());
if (objc_class_type)
return objc_class_type->getInterface();
- return NULL;
+ return nullptr;
}
clang::FieldDecl *
@@ -4387,37 +4563,37 @@ ClangASTType::AddFieldToRecordType (const char *name,
uint32_t bitfield_bit_size)
{
if (!IsValid() || !field_clang_type.IsValid())
- return NULL;
+ return nullptr;
- FieldDecl *field = NULL;
+ clang::FieldDecl *field = nullptr;
- clang::Expr *bit_width = NULL;
+ clang::Expr *bit_width = nullptr;
if (bitfield_bit_size != 0)
{
- APInt bitfield_bit_size_apint(m_ast->getTypeSize(m_ast->IntTy), bitfield_bit_size);
- bit_width = new (*m_ast)IntegerLiteral (*m_ast, bitfield_bit_size_apint, m_ast->IntTy, SourceLocation());
+ llvm::APInt bitfield_bit_size_apint(m_ast->getTypeSize(m_ast->IntTy), bitfield_bit_size);
+ bit_width = new (*m_ast)clang::IntegerLiteral (*m_ast, bitfield_bit_size_apint, m_ast->IntTy, clang::SourceLocation());
}
- RecordDecl *record_decl = GetAsRecordDecl ();
+ clang::RecordDecl *record_decl = GetAsRecordDecl ();
if (record_decl)
{
- field = FieldDecl::Create (*m_ast,
- record_decl,
- SourceLocation(),
- SourceLocation(),
- name ? &m_ast->Idents.get(name) : NULL, // Identifier
- field_clang_type.GetQualType(), // Field type
- NULL, // TInfo *
- bit_width, // BitWidth
- false, // Mutable
- ICIS_NoInit); // HasInit
+ field = clang::FieldDecl::Create (*m_ast,
+ record_decl,
+ clang::SourceLocation(),
+ clang::SourceLocation(),
+ name ? &m_ast->Idents.get(name) : nullptr, // Identifier
+ field_clang_type.GetQualType(), // Field type
+ nullptr, // TInfo *
+ bit_width, // BitWidth
+ false, // Mutable
+ clang::ICIS_NoInit); // HasInit
if (!name)
{
// Determine whether this field corresponds to an anonymous
// struct or union.
- if (const TagType *TagT = field->getType()->getAs<TagType>()) {
- if (RecordDecl *Rec = dyn_cast<RecordDecl>(TagT->getDecl()))
+ if (const clang::TagType *TagT = field->getType()->getAs<clang::TagType>()) {
+ if (clang::RecordDecl *Rec = llvm::dyn_cast<clang::RecordDecl>(TagT->getDecl()))
if (!Rec->getDeclName()) {
Rec->setAnonymousStructOrUnion(true);
field->setImplicit();
@@ -4439,7 +4615,7 @@ ClangASTType::AddFieldToRecordType (const char *name,
}
else
{
- ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl ();
+ clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl ();
if (class_interface_decl)
{
@@ -4447,13 +4623,13 @@ ClangASTType::AddFieldToRecordType (const char *name,
field_clang_type.GetCompleteType();
- field = ObjCIvarDecl::Create (*m_ast,
+ field = clang::ObjCIvarDecl::Create (*m_ast,
class_interface_decl,
- SourceLocation(),
- SourceLocation(),
- name ? &m_ast->Idents.get(name) : NULL, // Identifier
+ clang::SourceLocation(),
+ clang::SourceLocation(),
+ name ? &m_ast->Idents.get(name) : nullptr, // Identifier
field_clang_type.GetQualType(), // Field type
- NULL, // TypeSourceInfo *
+ nullptr, // TypeSourceInfo *
ConvertAccessTypeToObjCIvarAccessControl (access),
bit_width,
is_synthesized);
@@ -4474,49 +4650,49 @@ ClangASTType::AddFieldToRecordType (const char *name,
void
ClangASTType::BuildIndirectFields ()
{
- RecordDecl *record_decl = GetAsRecordDecl();
+ clang::RecordDecl *record_decl = GetAsRecordDecl();
if (!record_decl)
return;
- typedef llvm::SmallVector <IndirectFieldDecl *, 1> IndirectFieldVector;
+ typedef llvm::SmallVector <clang::IndirectFieldDecl *, 1> IndirectFieldVector;
IndirectFieldVector indirect_fields;
- RecordDecl::field_iterator field_pos;
- RecordDecl::field_iterator field_end_pos = record_decl->field_end();
- RecordDecl::field_iterator last_field_pos = field_end_pos;
+ clang::RecordDecl::field_iterator field_pos;
+ clang::RecordDecl::field_iterator field_end_pos = record_decl->field_end();
+ clang::RecordDecl::field_iterator last_field_pos = field_end_pos;
for (field_pos = record_decl->field_begin(); field_pos != field_end_pos; last_field_pos = field_pos++)
{
if (field_pos->isAnonymousStructOrUnion())
{
- QualType field_qual_type = field_pos->getType();
+ clang::QualType field_qual_type = field_pos->getType();
- const RecordType *field_record_type = field_qual_type->getAs<RecordType>();
+ const clang::RecordType *field_record_type = field_qual_type->getAs<clang::RecordType>();
if (!field_record_type)
continue;
- RecordDecl *field_record_decl = field_record_type->getDecl();
+ clang::RecordDecl *field_record_decl = field_record_type->getDecl();
if (!field_record_decl)
continue;
- for (RecordDecl::decl_iterator di = field_record_decl->decls_begin(), de = field_record_decl->decls_end();
+ for (clang::RecordDecl::decl_iterator di = field_record_decl->decls_begin(), de = field_record_decl->decls_end();
di != de;
++di)
{
- if (FieldDecl *nested_field_decl = dyn_cast<FieldDecl>(*di))
+ if (clang::FieldDecl *nested_field_decl = llvm::dyn_cast<clang::FieldDecl>(*di))
{
- NamedDecl **chain = new (*m_ast) NamedDecl*[2];
+ clang::NamedDecl **chain = new (*m_ast) clang::NamedDecl*[2];
chain[0] = *field_pos;
chain[1] = nested_field_decl;
- IndirectFieldDecl *indirect_field = IndirectFieldDecl::Create(*m_ast,
- record_decl,
- SourceLocation(),
- nested_field_decl->getIdentifier(),
- nested_field_decl->getType(),
- chain,
- 2);
+ clang::IndirectFieldDecl *indirect_field = clang::IndirectFieldDecl::Create(*m_ast,
+ record_decl,
+ clang::SourceLocation(),
+ nested_field_decl->getIdentifier(),
+ nested_field_decl->getType(),
+ chain,
+ 2);
indirect_field->setImplicit();
@@ -4525,14 +4701,14 @@ ClangASTType::BuildIndirectFields ()
indirect_fields.push_back(indirect_field);
}
- else if (IndirectFieldDecl *nested_indirect_field_decl = dyn_cast<IndirectFieldDecl>(*di))
+ else if (clang::IndirectFieldDecl *nested_indirect_field_decl = llvm::dyn_cast<clang::IndirectFieldDecl>(*di))
{
int nested_chain_size = nested_indirect_field_decl->getChainingSize();
- NamedDecl **chain = new (*m_ast) NamedDecl*[nested_chain_size + 1];
+ clang::NamedDecl **chain = new (*m_ast) clang::NamedDecl*[nested_chain_size + 1];
chain[0] = *field_pos;
int chain_index = 1;
- for (IndirectFieldDecl::chain_iterator nci = nested_indirect_field_decl->chain_begin(),
+ for (clang::IndirectFieldDecl::chain_iterator nci = nested_indirect_field_decl->chain_begin(),
nce = nested_indirect_field_decl->chain_end();
nci < nce;
++nci)
@@ -4541,13 +4717,13 @@ ClangASTType::BuildIndirectFields ()
chain_index++;
}
- IndirectFieldDecl *indirect_field = IndirectFieldDecl::Create(*m_ast,
- record_decl,
- SourceLocation(),
- nested_indirect_field_decl->getIdentifier(),
- nested_indirect_field_decl->getType(),
- chain,
- nested_chain_size + 1);
+ clang::IndirectFieldDecl *indirect_field = clang::IndirectFieldDecl::Create(*m_ast,
+ record_decl,
+ clang::SourceLocation(),
+ nested_indirect_field_decl->getIdentifier(),
+ nested_indirect_field_decl->getType(),
+ chain,
+ nested_chain_size + 1);
indirect_field->setImplicit();
@@ -4581,22 +4757,22 @@ ClangASTType::AddVariableToRecordType (const char *name,
const ClangASTType &var_type,
AccessType access)
{
- clang::VarDecl *var_decl = NULL;
+ clang::VarDecl *var_decl = nullptr;
if (!IsValid() || !var_type.IsValid())
- return NULL;
+ return nullptr;
- RecordDecl *record_decl = GetAsRecordDecl ();
+ clang::RecordDecl *record_decl = GetAsRecordDecl ();
if (record_decl)
{
- var_decl = VarDecl::Create (*m_ast, // ASTContext &
- record_decl, // DeclContext *
- SourceLocation(), // SourceLocation StartLoc
- SourceLocation(), // SourceLocation IdLoc
- name ? &m_ast->Idents.get(name) : NULL, // IdentifierInfo *
- var_type.GetQualType(), // Variable QualType
- NULL, // TypeSourceInfo *
- SC_Static); // StorageClass
+ var_decl = clang::VarDecl::Create (*m_ast, // ASTContext &
+ record_decl, // DeclContext *
+ clang::SourceLocation(), // clang::SourceLocation StartLoc
+ clang::SourceLocation(), // clang::SourceLocation IdLoc
+ name ? &m_ast->Idents.get(name) : nullptr, // clang::IdentifierInfo *
+ var_type.GetQualType(), // Variable clang::QualType
+ nullptr, // TypeSourceInfo *
+ clang::SC_Static); // StorageClass
if (var_decl)
{
var_decl->setAccess(ClangASTContext::ConvertAccessTypeToAccessSpecifier (access));
@@ -4611,7 +4787,7 @@ ClangASTType::AddVariableToRecordType (const char *name,
}
-CXXMethodDecl *
+clang::CXXMethodDecl *
ClangASTType::AddMethodToCXXRecordType (const char *name,
const ClangASTType &method_clang_type,
lldb::AccessType access,
@@ -4622,74 +4798,74 @@ ClangASTType::AddMethodToCXXRecordType (const char *name,
bool is_attr_used,
bool is_artificial)
{
- if (!IsValid() || !method_clang_type.IsValid() || name == NULL || name[0] == '\0')
- return NULL;
+ if (!IsValid() || !method_clang_type.IsValid() || name == nullptr || name[0] == '\0')
+ return nullptr;
- QualType record_qual_type(GetCanonicalQualType());
+ clang::QualType record_qual_type(GetCanonicalQualType());
- CXXRecordDecl *cxx_record_decl = record_qual_type->getAsCXXRecordDecl();
+ clang::CXXRecordDecl *cxx_record_decl = record_qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl == NULL)
- return NULL;
+ if (cxx_record_decl == nullptr)
+ return nullptr;
- QualType method_qual_type (method_clang_type.GetQualType());
+ clang::QualType method_qual_type (method_clang_type.GetQualType());
- CXXMethodDecl *cxx_method_decl = NULL;
+ clang::CXXMethodDecl *cxx_method_decl = nullptr;
- DeclarationName decl_name (&m_ast->Idents.get(name));
+ clang::DeclarationName decl_name (&m_ast->Idents.get(name));
- const clang::FunctionType *function_type = dyn_cast<FunctionType>(method_qual_type.getTypePtr());
+ const clang::FunctionType *function_type = llvm::dyn_cast<clang::FunctionType>(method_qual_type.getTypePtr());
- if (function_type == NULL)
- return NULL;
+ if (function_type == nullptr)
+ return nullptr;
- const FunctionProtoType *method_function_prototype (dyn_cast<FunctionProtoType>(function_type));
+ const clang::FunctionProtoType *method_function_prototype (llvm::dyn_cast<clang::FunctionProtoType>(function_type));
if (!method_function_prototype)
- return NULL;
+ return nullptr;
unsigned int num_params = method_function_prototype->getNumParams();
- CXXDestructorDecl *cxx_dtor_decl(NULL);
- CXXConstructorDecl *cxx_ctor_decl(NULL);
+ clang::CXXDestructorDecl *cxx_dtor_decl(nullptr);
+ clang::CXXConstructorDecl *cxx_ctor_decl(nullptr);
if (is_artificial)
- return NULL; // skip everything artificial
+ return nullptr; // skip everything artificial
if (name[0] == '~')
{
- cxx_dtor_decl = CXXDestructorDecl::Create (*m_ast,
- cxx_record_decl,
- SourceLocation(),
- DeclarationNameInfo (m_ast->DeclarationNames.getCXXDestructorName (m_ast->getCanonicalType (record_qual_type)), SourceLocation()),
- method_qual_type,
- NULL,
- is_inline,
- is_artificial);
+ cxx_dtor_decl = clang::CXXDestructorDecl::Create (*m_ast,
+ cxx_record_decl,
+ clang::SourceLocation(),
+ clang::DeclarationNameInfo (m_ast->DeclarationNames.getCXXDestructorName (m_ast->getCanonicalType (record_qual_type)), clang::SourceLocation()),
+ method_qual_type,
+ nullptr,
+ is_inline,
+ is_artificial);
cxx_method_decl = cxx_dtor_decl;
}
else if (decl_name == cxx_record_decl->getDeclName())
{
- cxx_ctor_decl = CXXConstructorDecl::Create (*m_ast,
- cxx_record_decl,
- SourceLocation(),
- DeclarationNameInfo (m_ast->DeclarationNames.getCXXConstructorName (m_ast->getCanonicalType (record_qual_type)), SourceLocation()),
- method_qual_type,
- NULL, // TypeSourceInfo *
- is_explicit,
- is_inline,
- is_artificial,
- false /*is_constexpr*/);
+ cxx_ctor_decl = clang::CXXConstructorDecl::Create (*m_ast,
+ cxx_record_decl,
+ clang::SourceLocation(),
+ clang::DeclarationNameInfo (m_ast->DeclarationNames.getCXXConstructorName (m_ast->getCanonicalType (record_qual_type)), clang::SourceLocation()),
+ method_qual_type,
+ nullptr, // TypeSourceInfo *
+ is_explicit,
+ is_inline,
+ is_artificial,
+ false /*is_constexpr*/);
cxx_method_decl = cxx_ctor_decl;
}
else
{
- clang::StorageClass SC = is_static ? SC_Static : SC_None;
- OverloadedOperatorKind op_kind = NUM_OVERLOADED_OPERATORS;
+ clang::StorageClass SC = is_static ? clang::SC_Static : clang::SC_None;
+ clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS;
if (IsOperator (name, op_kind))
{
- if (op_kind != NUM_OVERLOADED_OPERATORS)
+ if (op_kind != clang::NUM_OVERLOADED_OPERATORS)
{
// Check the number of operator parameters. Sometimes we have
// seen bad DWARF that doesn't correctly describe operators and
@@ -4697,50 +4873,50 @@ ClangASTType::AddMethodToCXXRecordType (const char *name,
// will assert and crash, so we need to make sure things are
// acceptable.
if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount (op_kind, num_params))
- return NULL;
- cxx_method_decl = CXXMethodDecl::Create (*m_ast,
- cxx_record_decl,
- SourceLocation(),
- DeclarationNameInfo (m_ast->DeclarationNames.getCXXOperatorName (op_kind), SourceLocation()),
- method_qual_type,
- NULL, // TypeSourceInfo *
- SC,
- is_inline,
- false /*is_constexpr*/,
- SourceLocation());
+ return nullptr;
+ cxx_method_decl = clang::CXXMethodDecl::Create (*m_ast,
+ cxx_record_decl,
+ clang::SourceLocation(),
+ clang::DeclarationNameInfo (m_ast->DeclarationNames.getCXXOperatorName (op_kind), clang::SourceLocation()),
+ method_qual_type,
+ nullptr, // TypeSourceInfo *
+ SC,
+ is_inline,
+ false /*is_constexpr*/,
+ clang::SourceLocation());
}
else if (num_params == 0)
{
// Conversion operators don't take params...
- cxx_method_decl = CXXConversionDecl::Create (*m_ast,
- cxx_record_decl,
- SourceLocation(),
- DeclarationNameInfo (m_ast->DeclarationNames.getCXXConversionFunctionName (m_ast->getCanonicalType (function_type->getReturnType())), SourceLocation()),
- method_qual_type,
- NULL, // TypeSourceInfo *
- is_inline,
- is_explicit,
- false /*is_constexpr*/,
- SourceLocation());
+ cxx_method_decl = clang::CXXConversionDecl::Create (*m_ast,
+ cxx_record_decl,
+ clang::SourceLocation(),
+ clang::DeclarationNameInfo (m_ast->DeclarationNames.getCXXConversionFunctionName (m_ast->getCanonicalType (function_type->getReturnType())), clang::SourceLocation()),
+ method_qual_type,
+ nullptr, // TypeSourceInfo *
+ is_inline,
+ is_explicit,
+ false /*is_constexpr*/,
+ clang::SourceLocation());
}
}
- if (cxx_method_decl == NULL)
+ if (cxx_method_decl == nullptr)
{
- cxx_method_decl = CXXMethodDecl::Create (*m_ast,
- cxx_record_decl,
- SourceLocation(),
- DeclarationNameInfo (decl_name, SourceLocation()),
- method_qual_type,
- NULL, // TypeSourceInfo *
- SC,
- is_inline,
- false /*is_constexpr*/,
- SourceLocation());
+ cxx_method_decl = clang::CXXMethodDecl::Create (*m_ast,
+ cxx_record_decl,
+ clang::SourceLocation(),
+ clang::DeclarationNameInfo (decl_name, clang::SourceLocation()),
+ method_qual_type,
+ nullptr, // TypeSourceInfo *
+ SC,
+ is_inline,
+ false /*is_constexpr*/,
+ clang::SourceLocation());
}
}
- AccessSpecifier access_specifier = ClangASTContext::ConvertAccessTypeToAccessSpecifier (access);
+ clang::AccessSpecifier access_specifier = ClangASTContext::ConvertAccessTypeToAccessSpecifier (access);
cxx_method_decl->setAccess (access_specifier);
cxx_method_decl->setVirtualAsWritten (is_virtual);
@@ -4750,24 +4926,24 @@ ClangASTType::AddMethodToCXXRecordType (const char *name,
// Populate the method decl with parameter decls
- llvm::SmallVector<ParmVarDecl *, 12> params;
+ llvm::SmallVector<clang::ParmVarDecl *, 12> params;
for (unsigned param_index = 0;
param_index < num_params;
++param_index)
{
- params.push_back (ParmVarDecl::Create (*m_ast,
- cxx_method_decl,
- SourceLocation(),
- SourceLocation(),
- NULL, // anonymous
- method_function_prototype->getParamType(param_index),
- NULL,
- SC_None,
- NULL));
+ params.push_back (clang::ParmVarDecl::Create (*m_ast,
+ cxx_method_decl,
+ clang::SourceLocation(),
+ clang::SourceLocation(),
+ nullptr, // anonymous
+ method_function_prototype->getParamType(param_index),
+ nullptr,
+ clang::SC_None,
+ nullptr));
}
- cxx_method_decl->setParams (ArrayRef<ParmVarDecl*>(params));
+ cxx_method_decl->setParams (llvm::ArrayRef<clang::ParmVarDecl*>(params));
cxx_record_decl->addDecl (cxx_method_decl);
@@ -4823,36 +4999,36 @@ ClangASTType::AddMethodToCXXRecordType (const char *name,
#pragma mark C++ Base Classes
-CXXBaseSpecifier *
+clang::CXXBaseSpecifier *
ClangASTType::CreateBaseClassSpecifier (AccessType access, bool is_virtual, bool base_of_class)
{
if (IsValid())
- return new CXXBaseSpecifier (SourceRange(),
- is_virtual,
- base_of_class,
- ClangASTContext::ConvertAccessTypeToAccessSpecifier (access),
- m_ast->getTrivialTypeSourceInfo (GetQualType()),
- SourceLocation());
- return NULL;
+ return new clang::CXXBaseSpecifier (clang::SourceRange(),
+ is_virtual,
+ base_of_class,
+ ClangASTContext::ConvertAccessTypeToAccessSpecifier (access),
+ m_ast->getTrivialTypeSourceInfo (GetQualType()),
+ clang::SourceLocation());
+ return nullptr;
}
void
-ClangASTType::DeleteBaseClassSpecifiers (CXXBaseSpecifier **base_classes, unsigned num_base_classes)
+ClangASTType::DeleteBaseClassSpecifiers (clang::CXXBaseSpecifier **base_classes, unsigned num_base_classes)
{
for (unsigned i=0; i<num_base_classes; ++i)
{
delete base_classes[i];
- base_classes[i] = NULL;
+ base_classes[i] = nullptr;
}
}
bool
-ClangASTType::SetBaseClassesForClassType (CXXBaseSpecifier const * const *base_classes,
+ClangASTType::SetBaseClassesForClassType (clang::CXXBaseSpecifier const * const *base_classes,
unsigned num_base_classes)
{
if (IsValid())
{
- CXXRecordDecl *cxx_record_decl = GetAsCXXRecordDecl();
+ clang::CXXRecordDecl *cxx_record_decl = GetAsCXXRecordDecl();
if (cxx_record_decl)
{
cxx_record_decl->setBases(base_classes, num_base_classes);
@@ -4867,8 +5043,8 @@ ClangASTType::SetObjCSuperClass (const ClangASTType &superclass_clang_type)
{
if (IsValid() && superclass_clang_type.IsValid())
{
- ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl ();
- ObjCInterfaceDecl *super_interface_decl = superclass_clang_type.GetAsObjCInterfaceDecl ();
+ clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl ();
+ clang::ObjCInterfaceDecl *super_interface_decl = superclass_clang_type.GetAsObjCInterfaceDecl ();
if (class_interface_decl && super_interface_decl)
{
class_interface_decl->setSuperClass(super_interface_decl);
@@ -4881,16 +5057,16 @@ ClangASTType::SetObjCSuperClass (const ClangASTType &superclass_clang_type)
bool
ClangASTType::AddObjCClassProperty (const char *property_name,
const ClangASTType &property_clang_type,
- ObjCIvarDecl *ivar_decl,
+ clang::ObjCIvarDecl *ivar_decl,
const char *property_setter_name,
const char *property_getter_name,
uint32_t property_attributes,
ClangASTMetadata *metadata)
{
- if (!IsValid() || !property_clang_type.IsValid() || property_name == NULL || property_name[0] == '\0')
+ if (!IsValid() || !property_clang_type.IsValid() || property_name == nullptr || property_name[0] == '\0')
return false;
- ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl ();
+ clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl ();
if (class_interface_decl)
{
@@ -4909,13 +5085,13 @@ ClangASTType::AddObjCClassProperty (const char *property_name,
else
prop_type_source = m_ast->getTrivialTypeSourceInfo (property_clang_type.GetQualType());
- ObjCPropertyDecl *property_decl = ObjCPropertyDecl::Create (*m_ast,
- class_interface_decl,
- SourceLocation(), // Source Location
- &m_ast->Idents.get(property_name),
- SourceLocation(), //Source Location for AT
- SourceLocation(), //Source location for (
- prop_type_source);
+ clang::ObjCPropertyDecl *property_decl = clang::ObjCPropertyDecl::Create (*m_ast,
+ class_interface_decl,
+ clang::SourceLocation(), // Source Location
+ &m_ast->Idents.get(property_name),
+ clang::SourceLocation(), //Source Location for AT
+ clang::SourceLocation(), //Source location for (
+ prop_type_source);
if (property_decl)
{
@@ -4924,9 +5100,9 @@ ClangASTType::AddObjCClassProperty (const char *property_name,
class_interface_decl->addDecl (property_decl);
- Selector setter_sel, getter_sel;
+ clang::Selector setter_sel, getter_sel;
- if (property_setter_name != NULL)
+ if (property_setter_name != nullptr)
{
std::string property_setter_no_colon(property_setter_name, strlen(property_setter_name) - 1);
clang::IdentifierInfo *setter_ident = &m_ast->Idents.get(property_setter_no_colon.c_str());
@@ -4943,7 +5119,7 @@ ClangASTType::AddObjCClassProperty (const char *property_name,
property_decl->setSetterName(setter_sel);
property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_setter);
- if (property_getter_name != NULL)
+ if (property_getter_name != nullptr)
{
clang::IdentifierInfo *getter_ident = &m_ast->Idents.get(property_getter_name);
getter_sel = m_ast->Selectors.getSelector(0, &getter_ident);
@@ -4979,75 +5155,75 @@ ClangASTType::AddObjCClassProperty (const char *property_name,
const bool isSynthesized = false;
const bool isImplicitlyDeclared = true;
const bool isDefined = false;
- const ObjCMethodDecl::ImplementationControl impControl = ObjCMethodDecl::None;
+ const clang::ObjCMethodDecl::ImplementationControl impControl = clang::ObjCMethodDecl::None;
const bool HasRelatedResultType = false;
- ObjCMethodDecl *getter = ObjCMethodDecl::Create (*m_ast,
- SourceLocation(),
- SourceLocation(),
- getter_sel,
- property_clang_type_to_access.GetQualType(),
- NULL,
- class_interface_decl,
- isInstance,
- isVariadic,
- isSynthesized,
- isImplicitlyDeclared,
- isDefined,
- impControl,
- HasRelatedResultType);
+ clang::ObjCMethodDecl *getter = clang::ObjCMethodDecl::Create (*m_ast,
+ clang::SourceLocation(),
+ clang::SourceLocation(),
+ getter_sel,
+ property_clang_type_to_access.GetQualType(),
+ nullptr,
+ class_interface_decl,
+ isInstance,
+ isVariadic,
+ isSynthesized,
+ isImplicitlyDeclared,
+ isDefined,
+ impControl,
+ HasRelatedResultType);
if (getter && metadata)
ClangASTContext::SetMetadata(m_ast, getter, *metadata);
- getter->setMethodParams(*m_ast, ArrayRef<ParmVarDecl*>(), ArrayRef<SourceLocation>());
+ getter->setMethodParams(*m_ast, llvm::ArrayRef<clang::ParmVarDecl*>(), llvm::ArrayRef<clang::SourceLocation>());
class_interface_decl->addDecl(getter);
}
if (!setter_sel.isNull() && !class_interface_decl->lookupInstanceMethod(setter_sel))
{
- QualType result_type = m_ast->VoidTy;
+ clang::QualType result_type = m_ast->VoidTy;
const bool isInstance = true;
const bool isVariadic = false;
const bool isSynthesized = false;
const bool isImplicitlyDeclared = true;
const bool isDefined = false;
- const ObjCMethodDecl::ImplementationControl impControl = ObjCMethodDecl::None;
+ const clang::ObjCMethodDecl::ImplementationControl impControl = clang::ObjCMethodDecl::None;
const bool HasRelatedResultType = false;
- ObjCMethodDecl *setter = ObjCMethodDecl::Create (*m_ast,
- SourceLocation(),
- SourceLocation(),
- setter_sel,
- result_type,
- NULL,
- class_interface_decl,
- isInstance,
- isVariadic,
- isSynthesized,
- isImplicitlyDeclared,
- isDefined,
- impControl,
- HasRelatedResultType);
+ clang::ObjCMethodDecl *setter = clang::ObjCMethodDecl::Create (*m_ast,
+ clang::SourceLocation(),
+ clang::SourceLocation(),
+ setter_sel,
+ result_type,
+ nullptr,
+ class_interface_decl,
+ isInstance,
+ isVariadic,
+ isSynthesized,
+ isImplicitlyDeclared,
+ isDefined,
+ impControl,
+ HasRelatedResultType);
if (setter && metadata)
ClangASTContext::SetMetadata(m_ast, setter, *metadata);
- llvm::SmallVector<ParmVarDecl *, 1> params;
+ llvm::SmallVector<clang::ParmVarDecl *, 1> params;
- params.push_back (ParmVarDecl::Create (*m_ast,
- setter,
- SourceLocation(),
- SourceLocation(),
- NULL, // anonymous
- property_clang_type_to_access.GetQualType(),
- NULL,
- SC_Auto,
- NULL));
+ params.push_back (clang::ParmVarDecl::Create (*m_ast,
+ setter,
+ clang::SourceLocation(),
+ clang::SourceLocation(),
+ nullptr, // anonymous
+ property_clang_type_to_access.GetQualType(),
+ nullptr,
+ clang::SC_Auto,
+ nullptr));
- setter->setMethodParams(*m_ast, ArrayRef<ParmVarDecl*>(params), ArrayRef<SourceLocation>());
+ setter->setMethodParams(*m_ast, llvm::ArrayRef<clang::ParmVarDecl*>(params), llvm::ArrayRef<clang::SourceLocation>());
class_interface_decl->addDecl(setter);
}
@@ -5062,33 +5238,33 @@ ClangASTType::AddObjCClassProperty (const char *property_name,
bool
ClangASTType::IsObjCClassTypeAndHasIVars (bool check_superclass) const
{
- ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl ();
+ clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl ();
if (class_interface_decl)
return ObjCDeclHasIVars (class_interface_decl, check_superclass);
return false;
}
-ObjCMethodDecl *
+clang::ObjCMethodDecl *
ClangASTType::AddMethodToObjCObjectType (const char *name, // the full symbol name as seen in the symbol table ("-[NString stringWithCString:]")
const ClangASTType &method_clang_type,
lldb::AccessType access,
bool is_artificial)
{
if (!IsValid() || !method_clang_type.IsValid())
- return NULL;
+ return nullptr;
- ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl();
+ clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl();
- if (class_interface_decl == NULL)
- return NULL;
+ if (class_interface_decl == nullptr)
+ return nullptr;
const char *selector_start = ::strchr (name, ' ');
- if (selector_start == NULL)
- return NULL;
+ if (selector_start == nullptr)
+ return nullptr;
selector_start++;
- llvm::SmallVector<IdentifierInfo *, 12> selector_idents;
+ llvm::SmallVector<clang::IdentifierInfo *, 12> selector_idents;
size_t len = 0;
const char *start;
@@ -5103,79 +5279,79 @@ ClangASTType::AddMethodToObjCObjectType (const char *name, // the full symbol n
bool has_arg = (start[len] == ':');
if (has_arg)
++num_selectors_with_args;
- selector_idents.push_back (&m_ast->Idents.get (StringRef (start, len)));
+ selector_idents.push_back (&m_ast->Idents.get (llvm::StringRef (start, len)));
if (has_arg)
len += 1;
}
if (selector_idents.size() == 0)
- return 0;
+ return nullptr;
clang::Selector method_selector = m_ast->Selectors.getSelector (num_selectors_with_args ? selector_idents.size() : 0,
selector_idents.data());
- QualType method_qual_type (method_clang_type.GetQualType());
+ clang::QualType method_qual_type (method_clang_type.GetQualType());
// Populate the method decl with parameter decls
const clang::Type *method_type(method_qual_type.getTypePtr());
- if (method_type == NULL)
- return NULL;
+ if (method_type == nullptr)
+ return nullptr;
- const FunctionProtoType *method_function_prototype (dyn_cast<FunctionProtoType>(method_type));
+ const clang::FunctionProtoType *method_function_prototype (llvm::dyn_cast<clang::FunctionProtoType>(method_type));
if (!method_function_prototype)
- return NULL;
+ return nullptr;
bool is_variadic = false;
bool is_synthesized = false;
bool is_defined = false;
- ObjCMethodDecl::ImplementationControl imp_control = ObjCMethodDecl::None;
+ clang::ObjCMethodDecl::ImplementationControl imp_control = clang::ObjCMethodDecl::None;
const unsigned num_args = method_function_prototype->getNumParams();
if (num_args != num_selectors_with_args)
- return NULL; // some debug information is corrupt. We are not going to deal with it.
+ return nullptr; // some debug information is corrupt. We are not going to deal with it.
- ObjCMethodDecl *objc_method_decl = ObjCMethodDecl::Create (*m_ast,
- SourceLocation(), // beginLoc,
- SourceLocation(), // endLoc,
- method_selector,
- method_function_prototype->getReturnType(),
- NULL, // TypeSourceInfo *ResultTInfo,
- GetDeclContextForType (),
- name[0] == '-',
- is_variadic,
- is_synthesized,
- true, // is_implicitly_declared; we force this to true because we don't have source locations
- is_defined,
- imp_control,
- false /*has_related_result_type*/);
+ clang::ObjCMethodDecl *objc_method_decl = clang::ObjCMethodDecl::Create (*m_ast,
+ clang::SourceLocation(), // beginLoc,
+ clang::SourceLocation(), // endLoc,
+ method_selector,
+ method_function_prototype->getReturnType(),
+ nullptr, // TypeSourceInfo *ResultTInfo,
+ GetDeclContextForType (),
+ name[0] == '-',
+ is_variadic,
+ is_synthesized,
+ true, // is_implicitly_declared; we force this to true because we don't have source locations
+ is_defined,
+ imp_control,
+ false /*has_related_result_type*/);
- if (objc_method_decl == NULL)
- return NULL;
+ if (objc_method_decl == nullptr)
+ return nullptr;
if (num_args > 0)
{
- llvm::SmallVector<ParmVarDecl *, 12> params;
+ llvm::SmallVector<clang::ParmVarDecl *, 12> params;
for (unsigned param_index = 0; param_index < num_args; ++param_index)
{
- params.push_back (ParmVarDecl::Create (*m_ast,
- objc_method_decl,
- SourceLocation(),
- SourceLocation(),
- NULL, // anonymous
- method_function_prototype->getParamType(param_index),
- NULL,
- SC_Auto,
- NULL));
+ params.push_back (clang::ParmVarDecl::Create (*m_ast,
+ objc_method_decl,
+ clang::SourceLocation(),
+ clang::SourceLocation(),
+ nullptr, // anonymous
+ method_function_prototype->getParamType(param_index),
+ nullptr,
+ clang::SC_Auto,
+ nullptr));
}
- objc_method_decl->setMethodParams(*m_ast, ArrayRef<ParmVarDecl*>(params), ArrayRef<SourceLocation>());
+ objc_method_decl->setMethodParams(*m_ast, llvm::ArrayRef<clang::ParmVarDecl*>(params), llvm::ArrayRef<clang::SourceLocation>());
}
class_interface_decl->addDecl (objc_method_decl);
@@ -5192,9 +5368,9 @@ clang::DeclContext *
ClangASTType::GetDeclContextForType () const
{
if (!IsValid())
- return NULL;
+ return nullptr;
- QualType qual_type(GetCanonicalQualType());
+ clang::QualType qual_type(GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
@@ -5216,13 +5392,13 @@ ClangASTType::GetDeclContextForType () const
case clang::Type::MemberPointer: break;
case clang::Type::Complex: break;
case clang::Type::ObjCObject: break;
- case clang::Type::ObjCInterface: return cast<ObjCObjectType>(qual_type.getTypePtr())->getInterface();
- case clang::Type::ObjCObjectPointer: return ClangASTType (m_ast, cast<ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType()).GetDeclContextForType();
- case clang::Type::Record: return cast<RecordType>(qual_type)->getDecl();
- case clang::Type::Enum: return cast<EnumType>(qual_type)->getDecl();
- case clang::Type::Typedef: return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetDeclContextForType();
- case clang::Type::Elaborated: return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetDeclContextForType();
- case clang::Type::Paren: return ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).GetDeclContextForType();
+ case clang::Type::ObjCInterface: return llvm::cast<clang::ObjCObjectType>(qual_type.getTypePtr())->getInterface();
+ case clang::Type::ObjCObjectPointer: return ClangASTType (m_ast, llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType()).GetDeclContextForType();
+ case clang::Type::Record: return llvm::cast<clang::RecordType>(qual_type)->getDecl();
+ case clang::Type::Enum: return llvm::cast<clang::EnumType>(qual_type)->getDecl();
+ case clang::Type::Typedef: return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetDeclContextForType();
+ case clang::Type::Elaborated: return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetDeclContextForType();
+ case clang::Type::Paren: return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetDeclContextForType();
case clang::Type::TypeOfExpr: break;
case clang::Type::TypeOf: break;
case clang::Type::Decltype: break;
@@ -5239,12 +5415,13 @@ ClangASTType::GetDeclContextForType () const
case clang::Type::InjectedClassName: break;
case clang::Type::DependentName: break;
case clang::Type::Atomic: break;
+ case clang::Type::Adjusted: break;
// pointer type decayed from an array or function type.
case clang::Type::Decayed: break;
}
// No DeclContext in this type...
- return NULL;
+ return nullptr;
}
bool
@@ -5254,18 +5431,18 @@ ClangASTType::SetDefaultAccessForRecordFields (int default_accessibility,
{
if (IsValid())
{
- RecordDecl *record_decl = GetAsRecordDecl();
+ clang::RecordDecl *record_decl = GetAsRecordDecl();
if (record_decl)
{
uint32_t field_idx;
- RecordDecl::field_iterator field, field_end;
+ clang::RecordDecl::field_iterator field, field_end;
for (field = record_decl->field_begin(), field_end = record_decl->field_end(), field_idx = 0;
field != field_end;
++field, ++field_idx)
{
// If no accessibility was assigned, assign the correct one
if (field_idx < num_assigned_accessibilities && assigned_accessibilities[field_idx] == clang::AS_none)
- field->setAccess ((AccessSpecifier)default_accessibility);
+ field->setAccess ((clang::AccessSpecifier)default_accessibility);
}
return true;
}
@@ -5280,14 +5457,14 @@ ClangASTType::SetHasExternalStorage (bool has_extern)
if (!IsValid())
return false;
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Record:
{
- CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
if (cxx_record_decl)
{
cxx_record_decl->setHasExternalLexicalStorage (has_extern);
@@ -5299,7 +5476,7 @@ ClangASTType::SetHasExternalStorage (bool has_extern)
case clang::Type::Enum:
{
- EnumDecl *enum_decl = cast<EnumType>(qual_type)->getDecl();
+ clang::EnumDecl *enum_decl = llvm::cast<clang::EnumType>(qual_type)->getDecl();
if (enum_decl)
{
enum_decl->setHasExternalLexicalStorage (has_extern);
@@ -5312,11 +5489,11 @@ ClangASTType::SetHasExternalStorage (bool has_extern)
case clang::Type::ObjCObject:
case clang::Type::ObjCInterface:
{
- const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
assert (objc_class_type);
if (objc_class_type)
{
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
if (class_interface_decl)
{
@@ -5329,13 +5506,13 @@ ClangASTType::SetHasExternalStorage (bool has_extern)
break;
case clang::Type::Typedef:
- return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).SetHasExternalStorage (has_extern);
+ return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).SetHasExternalStorage (has_extern);
case clang::Type::Elaborated:
- return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).SetHasExternalStorage (has_extern);
+ return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).SetHasExternalStorage (has_extern);
case clang::Type::Paren:
- return ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).SetHasExternalStorage (has_extern);
+ return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).SetHasExternalStorage (has_extern);
default:
break;
@@ -5348,17 +5525,17 @@ ClangASTType::SetTagTypeKind (int kind) const
{
if (IsValid())
{
- QualType tag_qual_type(GetQualType());
+ clang::QualType tag_qual_type(GetQualType());
const clang::Type *clang_type = tag_qual_type.getTypePtr();
if (clang_type)
{
- const TagType *tag_type = dyn_cast<TagType>(clang_type);
+ const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(clang_type);
if (tag_type)
{
- TagDecl *tag_decl = dyn_cast<TagDecl>(tag_type->getDecl());
+ clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(tag_type->getDecl());
if (tag_decl)
{
- tag_decl->setTagKind ((TagDecl::TagKind)kind);
+ tag_decl->setTagKind ((clang::TagDecl::TagKind)kind);
return true;
}
}
@@ -5375,14 +5552,14 @@ ClangASTType::StartTagDeclarationDefinition ()
{
if (IsValid())
{
- QualType qual_type (GetQualType());
+ clang::QualType qual_type (GetQualType());
const clang::Type *t = qual_type.getTypePtr();
if (t)
{
- const TagType *tag_type = dyn_cast<TagType>(t);
+ const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(t);
if (tag_type)
{
- TagDecl *tag_decl = tag_type->getDecl();
+ clang::TagDecl *tag_decl = tag_type->getDecl();
if (tag_decl)
{
tag_decl->startDefinition();
@@ -5390,10 +5567,10 @@ ClangASTType::StartTagDeclarationDefinition ()
}
}
- const ObjCObjectType *object_type = dyn_cast<ObjCObjectType>(t);
+ const clang::ObjCObjectType *object_type = llvm::dyn_cast<clang::ObjCObjectType>(t);
if (object_type)
{
- ObjCInterfaceDecl *interface_decl = object_type->getInterface();
+ clang::ObjCInterfaceDecl *interface_decl = object_type->getInterface();
if (interface_decl)
{
interface_decl->startDefinition();
@@ -5410,9 +5587,9 @@ ClangASTType::CompleteTagDeclarationDefinition ()
{
if (IsValid())
{
- QualType qual_type (GetQualType());
+ clang::QualType qual_type (GetQualType());
- CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
if (cxx_record_decl)
{
@@ -5421,11 +5598,11 @@ ClangASTType::CompleteTagDeclarationDefinition ()
return true;
}
- const EnumType *enum_type = dyn_cast<EnumType>(qual_type.getTypePtr());
+ const clang::EnumType *enum_type = llvm::dyn_cast<clang::EnumType>(qual_type.getTypePtr());
if (enum_type)
{
- EnumDecl *enum_decl = enum_type->getDecl();
+ clang::EnumDecl *enum_decl = enum_type->getDecl();
if (enum_decl)
{
@@ -5434,7 +5611,7 @@ ClangASTType::CompleteTagDeclarationDefinition ()
unsigned NumPositiveBits = 1;
unsigned NumNegativeBits = 0;
- QualType promotion_qual_type;
+ clang::QualType promotion_qual_type;
// If the enum integer type is less than an integer in bit width,
// then we must promote it to an integer size.
if (m_ast->getTypeSize(enum_decl->getIntegerType()) < m_ast->getTypeSize(m_ast->IntTy))
@@ -5470,27 +5647,27 @@ ClangASTType::AddEnumerationValueToEnumerationType (const ClangASTType &enumerat
{
if (IsValid() && enumerator_clang_type.IsValid() && name && name[0])
{
- QualType enum_qual_type (GetCanonicalQualType());
+ clang::QualType enum_qual_type (GetCanonicalQualType());
bool is_signed = false;
enumerator_clang_type.IsIntegerType (is_signed);
const clang::Type *clang_type = enum_qual_type.getTypePtr();
if (clang_type)
{
- const EnumType *enum_type = dyn_cast<EnumType>(clang_type);
+ const clang::EnumType *enum_type = llvm::dyn_cast<clang::EnumType>(clang_type);
if (enum_type)
{
llvm::APSInt enum_llvm_apsint(enum_value_bit_size, is_signed);
enum_llvm_apsint = enum_value;
- EnumConstantDecl *enumerator_decl =
- EnumConstantDecl::Create (*m_ast,
- enum_type->getDecl(),
- SourceLocation(),
- name ? &m_ast->Idents.get(name) : NULL, // Identifier
- enumerator_clang_type.GetQualType(),
- NULL,
- enum_llvm_apsint);
+ clang::EnumConstantDecl *enumerator_decl =
+ clang::EnumConstantDecl::Create (*m_ast,
+ enum_type->getDecl(),
+ clang::SourceLocation(),
+ name ? &m_ast->Idents.get(name) : nullptr, // Identifier
+ enumerator_clang_type.GetQualType(),
+ nullptr,
+ enum_llvm_apsint);
if (enumerator_decl)
{
@@ -5512,14 +5689,14 @@ ClangASTType::AddEnumerationValueToEnumerationType (const ClangASTType &enumerat
ClangASTType
ClangASTType::GetEnumerationIntegerType () const
{
- QualType enum_qual_type (GetCanonicalQualType());
+ clang::QualType enum_qual_type (GetCanonicalQualType());
const clang::Type *clang_type = enum_qual_type.getTypePtr();
if (clang_type)
{
- const EnumType *enum_type = dyn_cast<EnumType>(clang_type);
+ const clang::EnumType *enum_type = llvm::dyn_cast<clang::EnumType>(clang_type);
if (enum_type)
{
- EnumDecl *enum_decl = enum_type->getDecl();
+ clang::EnumDecl *enum_decl = enum_type->getDecl();
if (enum_decl)
return ClangASTType (m_ast, enum_decl->getIntegerType());
}
@@ -5544,7 +5721,7 @@ ClangASTType::ConvertStringToFloatValue (const char *s, uint8_t *dst, size_t dst
{
if (IsValid())
{
- QualType qual_type (GetCanonicalQualType());
+ clang::QualType qual_type (GetCanonicalQualType());
uint32_t count = 0;
bool is_complex = false;
if (IsFloatingPointType (count, is_complex))
@@ -5553,8 +5730,8 @@ ClangASTType::ConvertStringToFloatValue (const char *s, uint8_t *dst, size_t dst
if (count != 1)
return false;
- StringRef s_sref(s);
- APFloat ap_float(m_ast->getFloatTypeSemantics(qual_type), s_sref);
+ llvm::StringRef s_sref(s);
+ llvm::APFloat ap_float(m_ast->getFloatTypeSemantics(qual_type), s_sref);
const uint64_t bit_size = m_ast->getTypeSize (qual_type);
const uint64_t byte_size = bit_size / 8;
@@ -5602,30 +5779,30 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
if (!IsValid())
return;
- QualType qual_type(GetQualType());
+ clang::QualType qual_type(GetQualType());
switch (qual_type->getTypeClass())
{
case clang::Type::Record:
if (GetCompleteType ())
{
- const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
- const RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
assert(record_decl);
uint32_t field_bit_offset = 0;
uint32_t field_byte_offset = 0;
- const ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(record_decl);
+ const clang::ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(record_decl);
uint32_t child_idx = 0;
- const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
if (cxx_record_decl)
{
// We might have base classes to print out first
- CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ clang::CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
base_class != base_class_end;
++base_class)
{
- const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+ const clang::CXXRecordDecl *base_class_decl = llvm::cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl());
// Skip empty base classes
if (verbose == false && ClangASTContext::RecordHasFields(base_class_decl) == false)
@@ -5642,13 +5819,13 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
else
s->PutChar(',');
- QualType base_class_qual_type = base_class->getType();
+ clang::QualType base_class_qual_type = base_class->getType();
std::string base_class_type_name(base_class_qual_type.getAsString());
// Indent and print the base class type name
s->Printf("\n%*s%s ", depth + DEPTH_INCREMENT, "", base_class_type_name.c_str());
- std::pair<uint64_t, unsigned> base_class_type_info = m_ast->getTypeInfo(base_class_qual_type);
+ clang::TypeInfo base_class_type_info = m_ast->getTypeInfo(base_class_qual_type);
// Dump the value of the member
ClangASTType base_clang_type(m_ast, base_class_qual_type);
@@ -5657,7 +5834,7 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
base_clang_type.GetFormat(), // The format with which to display the member
data, // Data buffer containing all bytes for this type
data_byte_offset + field_byte_offset,// Offset into "data" where to grab value from
- base_class_type_info.first / 8, // Size of this type in bytes
+ base_class_type_info.Width / 8, // Size of this type in bytes
0, // Bitfield bit size
0, // Bitfield bit offset
show_types, // Boolean indicating if we should show the variable types
@@ -5669,7 +5846,7 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
}
}
uint32_t field_idx = 0;
- RecordDecl::field_iterator field, field_end;
+ clang::RecordDecl::field_iterator field, field_end;
for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx, ++child_idx)
{
// Print the starting squiggly bracket (if this is the
@@ -5683,11 +5860,11 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
// Indent
s->Printf("\n%*s", depth + DEPTH_INCREMENT, "");
- QualType field_type = field->getType();
+ clang::QualType field_type = field->getType();
// Print the member type if requested
// Figure out the type byte size (field_type_info.first) and
// alignment (field_type_info.second) from the AST context.
- std::pair<uint64_t, unsigned> field_type_info = m_ast->getTypeInfo(field_type);
+ clang::TypeInfo field_type_info = m_ast->getTypeInfo(field_type);
assert(field_idx < record_layout.getFieldCount());
// Figure out the field offset within the current struct/union/class type
field_bit_offset = record_layout.getFieldOffset (field_idx);
@@ -5716,7 +5893,7 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
field_clang_type.GetFormat(), // The format with which to display the member
data, // Data buffer containing all bytes for this type
data_byte_offset + field_byte_offset,// Offset into "data" where to grab value from
- field_type_info.first / 8, // Size of this type in bytes
+ field_type_info.Width / 8, // Size of this type in bytes
field_bitfield_bit_size, // Bitfield bit size
field_bitfield_bit_offset, // Bitfield bit offset
show_types, // Boolean indicating if we should show the variable types
@@ -5734,10 +5911,10 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
case clang::Type::Enum:
if (GetCompleteType ())
{
- const EnumType *enum_type = cast<EnumType>(qual_type.getTypePtr());
- const EnumDecl *enum_decl = enum_type->getDecl();
+ const clang::EnumType *enum_type = llvm::cast<clang::EnumType>(qual_type.getTypePtr());
+ const clang::EnumDecl *enum_decl = enum_type->getDecl();
assert(enum_decl);
- EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
+ clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
lldb::offset_t offset = data_byte_offset;
const int64_t enum_value = data.GetMaxU64Bitfield(&offset, data_byte_size, bitfield_bit_size, bitfield_bit_offset);
for (enum_pos = enum_decl->enumerator_begin(), enum_end_pos = enum_decl->enumerator_end(); enum_pos != enum_end_pos; ++enum_pos)
@@ -5756,9 +5933,9 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
case clang::Type::ConstantArray:
{
- const ConstantArrayType *array = cast<ConstantArrayType>(qual_type.getTypePtr());
+ const clang::ConstantArrayType *array = llvm::cast<clang::ConstantArrayType>(qual_type.getTypePtr());
bool is_array_of_characters = false;
- QualType element_qual_type = array->getElementType();
+ clang::QualType element_qual_type = array->getElementType();
const clang::Type *canonical_type = element_qual_type->getCanonicalTypeInternal().getTypePtr();
if (canonical_type)
@@ -5766,11 +5943,11 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
const uint64_t element_count = array->getSize().getLimitedValue();
- std::pair<uint64_t, unsigned> field_type_info = m_ast->getTypeInfo(element_qual_type);
+ clang::TypeInfo field_type_info = m_ast->getTypeInfo(element_qual_type);
uint32_t element_idx = 0;
uint32_t element_offset = 0;
- uint64_t element_byte_size = field_type_info.first / 8;
+ uint64_t element_byte_size = field_type_info.Width / 8;
uint32_t element_stride = element_byte_size;
if (is_array_of_characters)
@@ -5825,12 +6002,12 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
case clang::Type::Typedef:
{
- QualType typedef_qual_type = cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType();
+ clang::QualType typedef_qual_type = llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType();
ClangASTType typedef_clang_type (m_ast, typedef_qual_type);
lldb::Format typedef_format = typedef_clang_type.GetFormat();
- std::pair<uint64_t, unsigned> typedef_type_info = m_ast->getTypeInfo(typedef_qual_type);
- uint64_t typedef_byte_size = typedef_type_info.first / 8;
+ clang::TypeInfo typedef_type_info = m_ast->getTypeInfo(typedef_qual_type);
+ uint64_t typedef_byte_size = typedef_type_info.Width / 8;
return typedef_clang_type.DumpValue (exe_ctx,
s, // Stream to dump to
@@ -5849,11 +6026,11 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
case clang::Type::Elaborated:
{
- QualType elaborated_qual_type = cast<ElaboratedType>(qual_type)->getNamedType();
+ clang::QualType elaborated_qual_type = llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType();
ClangASTType elaborated_clang_type (m_ast, elaborated_qual_type);
lldb::Format elaborated_format = elaborated_clang_type.GetFormat();
- std::pair<uint64_t, unsigned> elaborated_type_info = m_ast->getTypeInfo(elaborated_qual_type);
- uint64_t elaborated_byte_size = elaborated_type_info.first / 8;
+ clang::TypeInfo elaborated_type_info = m_ast->getTypeInfo(elaborated_qual_type);
+ uint64_t elaborated_byte_size = elaborated_type_info.Width / 8;
return elaborated_clang_type.DumpValue (exe_ctx,
s, // Stream to dump to
@@ -5872,12 +6049,12 @@ ClangASTType::DumpValue (ExecutionContext *exe_ctx,
case clang::Type::Paren:
{
- QualType desugar_qual_type = cast<ParenType>(qual_type)->desugar();
+ clang::QualType desugar_qual_type = llvm::cast<clang::ParenType>(qual_type)->desugar();
ClangASTType desugar_clang_type (m_ast, desugar_qual_type);
lldb::Format desugar_format = desugar_clang_type.GetFormat();
- std::pair<uint64_t, unsigned> desugar_type_info = m_ast->getTypeInfo(desugar_qual_type);
- uint64_t desugar_byte_size = desugar_type_info.first / 8;
+ clang::TypeInfo desugar_type_info = m_ast->getTypeInfo(desugar_qual_type);
+ uint64_t desugar_byte_size = desugar_type_info.Width / 8;
return desugar_clang_type.DumpValue (exe_ctx,
s, // Stream to dump to
@@ -5933,19 +6110,19 @@ ClangASTType::DumpTypeValue (Stream *s,
}
else
{
- QualType qual_type(GetQualType());
+ clang::QualType qual_type(GetQualType());
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
{
case clang::Type::Typedef:
{
- QualType typedef_qual_type = cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType();
+ clang::QualType typedef_qual_type = llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType();
ClangASTType typedef_clang_type (m_ast, typedef_qual_type);
if (format == eFormatDefault)
format = typedef_clang_type.GetFormat();
- std::pair<uint64_t, unsigned> typedef_type_info = m_ast->getTypeInfo(typedef_qual_type);
- uint64_t typedef_byte_size = typedef_type_info.first / 8;
+ clang::TypeInfo typedef_type_info = m_ast->getTypeInfo(typedef_qual_type);
+ uint64_t typedef_byte_size = typedef_type_info.Width / 8;
return typedef_clang_type.DumpTypeValue (s,
format, // The format with which to display the element
@@ -5963,10 +6140,10 @@ ClangASTType::DumpTypeValue (Stream *s,
// its enumeration string value, else just display it as requested.
if ((format == eFormatEnum || format == eFormatDefault) && GetCompleteType ())
{
- const EnumType *enum_type = cast<EnumType>(qual_type.getTypePtr());
- const EnumDecl *enum_decl = enum_type->getDecl();
+ const clang::EnumType *enum_type = llvm::cast<clang::EnumType>(qual_type.getTypePtr());
+ const clang::EnumDecl *enum_decl = enum_type->getDecl();
assert(enum_decl);
- EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
+ clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
const bool is_signed = qual_type->isSignedIntegerOrEnumerationType();
lldb::offset_t offset = byte_offset;
if (is_signed)
@@ -6093,7 +6270,7 @@ ClangASTType::DumpSummary (ExecutionContext *exe_ctx,
if (process)
{
lldb::offset_t offset = data_byte_offset;
- lldb::addr_t pointer_addresss = data.GetMaxU64(&offset, data_byte_size);
+ lldb::addr_t pointer_address = data.GetMaxU64(&offset, data_byte_size);
std::vector<uint8_t> buf;
if (length > 0)
buf.resize (length);
@@ -6105,7 +6282,7 @@ ClangASTType::DumpSummary (ExecutionContext *exe_ctx,
size_t bytes_read;
size_t total_cstr_len = 0;
Error error;
- while ((bytes_read = process->ReadMemory (pointer_addresss, &buf.front(), buf.size(), error)) > 0)
+ while ((bytes_read = process->ReadMemory (pointer_address, &buf.front(), buf.size(), error)) > 0)
{
const size_t len = strlen((const char *)&buf.front());
if (len == 0)
@@ -6116,7 +6293,7 @@ ClangASTType::DumpSummary (ExecutionContext *exe_ctx,
total_cstr_len += len;
if (len < buf.size())
break;
- pointer_addresss += total_cstr_len;
+ pointer_address += total_cstr_len;
}
if (total_cstr_len > 0)
s->PutChar ('"');
@@ -6142,10 +6319,10 @@ ClangASTType::DumpTypeDescription (Stream *s) const
{
if (IsValid())
{
- QualType qual_type(GetQualType());
+ clang::QualType qual_type(GetQualType());
- SmallVector<char, 1024> buf;
- raw_svector_ostream llvm_ostrm (buf);
+ llvm::SmallVector<char, 1024> buf;
+ llvm::raw_svector_ostream llvm_ostrm (buf);
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class)
@@ -6155,14 +6332,14 @@ ClangASTType::DumpTypeDescription (Stream *s) const
{
GetCompleteType ();
- const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
assert (objc_class_type);
if (objc_class_type)
{
- ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
if (class_interface_decl)
{
- PrintingPolicy policy = m_ast->getPrintingPolicy();
+ clang::PrintingPolicy policy = m_ast->getPrintingPolicy();
class_interface_decl->print(llvm_ostrm, policy, s->GetIndentLevel());
}
}
@@ -6171,10 +6348,10 @@ ClangASTType::DumpTypeDescription (Stream *s) const
case clang::Type::Typedef:
{
- const TypedefType *typedef_type = qual_type->getAs<TypedefType>();
+ const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>();
if (typedef_type)
{
- const TypedefNameDecl *typedef_decl = typedef_type->getDecl();
+ const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl();
std::string clang_typedef_name (typedef_decl->getQualifiedNameAsString());
if (!clang_typedef_name.empty())
{
@@ -6186,20 +6363,20 @@ ClangASTType::DumpTypeDescription (Stream *s) const
break;
case clang::Type::Elaborated:
- ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).DumpTypeDescription(s);
+ ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).DumpTypeDescription(s);
return;
case clang::Type::Paren:
- ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).DumpTypeDescription(s);
+ ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).DumpTypeDescription(s);
return;
case clang::Type::Record:
{
GetCompleteType ();
- const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
- const RecordDecl *record_decl = record_type->getDecl();
- const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
if (cxx_record_decl)
cxx_record_decl->print(llvm_ostrm, m_ast->getPrintingPolicy(), s->GetIndentLevel());
@@ -6210,10 +6387,10 @@ ClangASTType::DumpTypeDescription (Stream *s) const
default:
{
- const TagType *tag_type = dyn_cast<TagType>(qual_type.getTypePtr());
+ const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
if (tag_type)
{
- TagDecl *tag_decl = tag_type->getDecl();
+ clang::TagDecl *tag_decl = tag_type->getDecl();
if (tag_decl)
tag_decl->print(llvm_ostrm, 0);
}
@@ -6471,19 +6648,19 @@ ClangASTType::ReadFromMemory (lldb_private::ExecutionContext *exe_ctx,
}
uint8_t* dst = (uint8_t*)data.PeekData(0, byte_size);
- if (dst != NULL)
+ if (dst != nullptr)
{
if (address_type == eAddressTypeHost)
{
if (addr == 0)
return false;
// The address is an address in this process, so just copy it
- memcpy (dst, (uint8_t*)NULL + addr, byte_size);
+ memcpy (dst, (uint8_t*)nullptr + addr, byte_size);
return true;
}
else
{
- Process *process = NULL;
+ Process *process = nullptr;
if (exe_ctx)
process = exe_ctx->GetProcessPtr();
if (process)
@@ -6525,7 +6702,7 @@ ClangASTType::WriteToMemory (lldb_private::ExecutionContext *exe_ctx,
}
else
{
- Process *process = NULL;
+ Process *process = nullptr;
if (exe_ctx)
process = exe_ctx->GetProcessPtr();
if (process)
@@ -6539,11 +6716,11 @@ ClangASTType::WriteToMemory (lldb_private::ExecutionContext *exe_ctx,
}
-//CXXRecordDecl *
+//clang::CXXRecordDecl *
//ClangASTType::GetAsCXXRecordDecl (lldb::clang_type_t opaque_clang_qual_type)
//{
// if (opaque_clang_qual_type)
-// return QualType::getFromOpaquePtr(opaque_clang_qual_type)->getAsCXXRecordDecl();
+// return clang::QualType::getFromOpaquePtr(opaque_clang_qual_type)->getAsCXXRecordDecl();
// return NULL;
//}
@@ -6561,3 +6738,4 @@ lldb_private::operator != (const lldb_private::ClangASTType &lhs, const lldb_pri
}
+
diff --git a/source/Symbol/ClangExternalASTSourceCallbacks.cpp b/source/Symbol/ClangExternalASTSourceCallbacks.cpp
index b2328d6e5b42..bdc32654cc10 100644
--- a/source/Symbol/ClangExternalASTSourceCallbacks.cpp
+++ b/source/Symbol/ClangExternalASTSourceCallbacks.cpp
@@ -14,7 +14,7 @@
// Other libraries and framework includes
// Clang headers like to use NDEBUG inside of them to enable/disable debug
-// releated features using "#ifndef NDEBUG" preprocessor blocks to do one thing
+// related features using "#ifndef NDEBUG" preprocessor blocks to do one thing
// or another. This is bad because it means that if clang was built in release
// mode, it assumes that you are building in release mode which is not always
// the case. You can end up with functions that are defined as empty in header
diff --git a/source/Symbol/ClangExternalASTSourceCommon.cpp b/source/Symbol/ClangExternalASTSourceCommon.cpp
index 697dc7eec493..650d252a8fc3 100644
--- a/source/Symbol/ClangExternalASTSourceCommon.cpp
+++ b/source/Symbol/ClangExternalASTSourceCommon.cpp
@@ -36,7 +36,7 @@ ClangExternalASTSourceCommon::GetMetadata (const void *object)
if (HasMetadata (object))
return &m_metadata[object];
else
- return NULL;
+ return nullptr;
}
void
diff --git a/source/Symbol/CompileUnit.cpp b/source/Symbol/CompileUnit.cpp
index 62ae1cc1cbe0..f99ca53d9629 100644
--- a/source/Symbol/CompileUnit.cpp
+++ b/source/Symbol/CompileUnit.cpp
@@ -99,11 +99,11 @@ CompileUnit::GetDescription(Stream *s, lldb::DescriptionLevel level) const
void
CompileUnit::Dump(Stream *s, bool show_context) const
{
- s->Printf("%p: ", this);
+ s->Printf("%p: ", static_cast<const void*>(this));
s->Indent();
- *s << "CompileUnit" << (const UserID&)*this
- << ", language = \"" << (const Language&)*this
- << "\", file = '" << (const FileSpec&)*this << "'\n";
+ *s << "CompileUnit" << static_cast<const UserID&>(*this)
+ << ", language = \"" << reinterpret_cast<const Language&>(*this)
+ << "\", file = '" << static_cast<const FileSpec&>(*this) << "'\n";
// m_types.Dump(s);
@@ -237,7 +237,7 @@ CompileUnit::GetLanguage()
LineTable*
CompileUnit::GetLineTable()
{
- if (m_line_table_ap.get() == NULL)
+ if (m_line_table_ap.get() == nullptr)
{
if (m_flags.IsClear(flagsParsedLineTable))
{
@@ -257,7 +257,7 @@ CompileUnit::GetLineTable()
void
CompileUnit::SetLineTable(LineTable* line_table)
{
- if (line_table == NULL)
+ if (line_table == nullptr)
m_flags.Clear(flagsParsedLineTable);
else
m_flags.Set(flagsParsedLineTable);
@@ -267,7 +267,7 @@ CompileUnit::SetLineTable(LineTable* line_table)
VariableListSP
CompileUnit::GetVariableList(bool can_create)
{
- if (m_variables.get() == NULL && can_create)
+ if (m_variables.get() == nullptr && can_create)
{
SymbolContext sc;
CalculateSymbolContext(&sc);
@@ -353,7 +353,7 @@ CompileUnit::ResolveSymbolContext
{
LineTable *line_table = sc.comp_unit->GetLineTable();
- if (line_table != NULL)
+ if (line_table != nullptr)
{
uint32_t found_line;
uint32_t line_idx;
diff --git a/source/Symbol/DWARFCallFrameInfo.cpp b/source/Symbol/DWARFCallFrameInfo.cpp
index d3d962896694..a9da631eb452 100644
--- a/source/Symbol/DWARFCallFrameInfo.cpp
+++ b/source/Symbol/DWARFCallFrameInfo.cpp
@@ -55,7 +55,7 @@ DWARFCallFrameInfo::GetUnwindPlan (Address addr, UnwindPlan& unwind_plan)
// Make sure that the Address we're searching for is the same object file
// as this DWARFCallFrameInfo, we only store File offsets in m_fde_index.
ModuleSP module_sp = addr.GetModule();
- if (module_sp.get() == NULL || module_sp->GetObjectFile() == NULL || module_sp->GetObjectFile() != &m_objfile)
+ if (module_sp.get() == nullptr || module_sp->GetObjectFile() == nullptr || module_sp->GetObjectFile() != &m_objfile)
return false;
if (GetFDEEntryByFileAddress (addr.GetFileAddress(), fde_entry) == false)
@@ -70,10 +70,10 @@ DWARFCallFrameInfo::GetAddressRange (Address addr, AddressRange &range)
// Make sure that the Address we're searching for is the same object file
// as this DWARFCallFrameInfo, we only store File offsets in m_fde_index.
ModuleSP module_sp = addr.GetModule();
- if (module_sp.get() == NULL || module_sp->GetObjectFile() == NULL || module_sp->GetObjectFile() != &m_objfile)
+ if (module_sp.get() == nullptr || module_sp->GetObjectFile() == nullptr || module_sp->GetObjectFile() != &m_objfile)
return false;
- if (m_section_sp.get() == NULL || m_section_sp->IsEncrypted())
+ if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted())
return false;
GetFDEIndex();
FDEEntryMap::Entry *fde_entry = m_fde_index.FindEntryThatContains (addr.GetFileAddress());
@@ -87,7 +87,7 @@ DWARFCallFrameInfo::GetAddressRange (Address addr, AddressRange &range)
bool
DWARFCallFrameInfo::GetFDEEntryByFileAddress (addr_t file_addr, FDEEntryMap::Entry &fde_entry)
{
- if (m_section_sp.get() == NULL || m_section_sp->IsEncrypted())
+ if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted())
return false;
GetFDEIndex();
@@ -97,7 +97,7 @@ DWARFCallFrameInfo::GetFDEEntryByFileAddress (addr_t file_addr, FDEEntryMap::Ent
FDEEntryMap::Entry *fde = m_fde_index.FindEntryThatContains (file_addr);
- if (fde == NULL)
+ if (fde == nullptr)
return false;
fde_entry = *fde;
@@ -131,12 +131,12 @@ DWARFCallFrameInfo::GetCIE(dw_offset_t cie_offset)
if (pos != m_cie_map.end())
{
// Parse and cache the CIE
- if (pos->second.get() == NULL)
+ if (pos->second.get() == nullptr)
pos->second = ParseCIE (cie_offset);
return pos->second.get();
}
- return NULL;
+ return nullptr;
}
DWARFCallFrameInfo::CIESP
@@ -146,9 +146,17 @@ DWARFCallFrameInfo::ParseCIE (const dw_offset_t cie_offset)
lldb::offset_t offset = cie_offset;
if (m_cfi_data_initialized == false)
GetCFIData();
- const uint32_t length = m_cfi_data.GetU32(&offset);
- const dw_offset_t cie_id = m_cfi_data.GetU32(&offset);
- const dw_offset_t end_offset = cie_offset + length + 4;
+ uint32_t length = m_cfi_data.GetU32(&offset);
+ dw_offset_t cie_id, end_offset;
+ bool is_64bit = (length == UINT32_MAX);
+ if (is_64bit) {
+ length = m_cfi_data.GetU64(&offset);
+ cie_id = m_cfi_data.GetU64(&offset);
+ end_offset = cie_offset + length + 12;
+ } else {
+ cie_id = m_cfi_data.GetU32(&offset);
+ end_offset = cie_offset + length + 4;
+ }
if (length > 0 && ((!m_is_eh_frame && cie_id == UINT32_MAX) || (m_is_eh_frame && cie_id == 0ul)))
{
size_t i;
@@ -318,7 +326,7 @@ DWARFCallFrameInfo::GetCFIData()
void
DWARFCallFrameInfo::GetFDEIndex ()
{
- if (m_section_sp.get() == NULL || m_section_sp->IsEncrypted())
+ if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted())
return;
if (m_fde_index_initialized)
@@ -337,9 +345,19 @@ DWARFCallFrameInfo::GetFDEIndex ()
while (m_cfi_data.ValidOffsetForDataOfSize (offset, 8))
{
const dw_offset_t current_entry = offset;
+ dw_offset_t cie_id, next_entry, cie_offset;
uint32_t len = m_cfi_data.GetU32 (&offset);
- dw_offset_t next_entry = current_entry + len + 4;
- dw_offset_t cie_id = m_cfi_data.GetU32 (&offset);
+ bool is_64bit = (len == UINT32_MAX);
+ if (is_64bit) {
+ len = m_cfi_data.GetU64 (&offset);
+ cie_id = m_cfi_data.GetU64 (&offset);
+ next_entry = current_entry + len + 12;
+ cie_offset = current_entry + 12 - cie_id;
+ } else {
+ cie_id = m_cfi_data.GetU32 (&offset);
+ next_entry = current_entry + len + 4;
+ cie_offset = current_entry + 4 - cie_id;
+ }
if (cie_id == 0 || cie_id == UINT32_MAX || len == 0)
{
@@ -348,7 +366,6 @@ DWARFCallFrameInfo::GetFDEIndex ()
continue;
}
- const dw_offset_t cie_offset = current_entry + 4 - cie_id;
const CIE *cie = GetCIE (cie_offset);
if (cie)
{
@@ -381,14 +398,21 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr
lldb::offset_t offset = dwarf_offset;
lldb::offset_t current_entry = offset;
- if (m_section_sp.get() == NULL || m_section_sp->IsEncrypted())
+ if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted())
return false;
if (m_cfi_data_initialized == false)
GetCFIData();
uint32_t length = m_cfi_data.GetU32 (&offset);
- dw_offset_t cie_offset = m_cfi_data.GetU32 (&offset);
+ dw_offset_t cie_offset;
+ bool is_64bit = (length == UINT32_MAX);
+ if (is_64bit) {
+ length = m_cfi_data.GetU64 (&offset);
+ cie_offset = m_cfi_data.GetU64 (&offset);
+ } else {
+ cie_offset = m_cfi_data.GetU32 (&offset);
+ }
assert (cie_offset != 0 && cie_offset != UINT32_MAX);
@@ -398,7 +422,7 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr
if (m_is_eh_frame)
{
unwind_plan.SetSourceName ("eh_frame CFI");
- cie_offset = current_entry + 4 - cie_offset;
+ cie_offset = current_entry + (is_64bit ? 12 : 4) - cie_offset;
unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
}
else
@@ -413,9 +437,9 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr
unwind_plan.SetSourcedFromCompiler (eLazyBoolYes);
const CIE *cie = GetCIE (cie_offset);
- assert (cie != NULL);
+ assert (cie != nullptr);
- const dw_offset_t end_offset = current_entry + length + 4;
+ const dw_offset_t end_offset = current_entry + length + (is_64bit ? 12 : 4);
const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();
const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;
diff --git a/source/Symbol/FuncUnwinders.cpp b/source/Symbol/FuncUnwinders.cpp
index 134dbf5f50db..95fc81747859 100644
--- a/source/Symbol/FuncUnwinders.cpp
+++ b/source/Symbol/FuncUnwinders.cpp
@@ -28,13 +28,11 @@ using namespace lldb_private;
FuncUnwinders::FuncUnwinders
(
UnwindTable& unwind_table,
- const lldb::UnwindAssemblySP& assembly_profiler,
AddressRange range
) :
m_unwind_table(unwind_table),
- m_assembly_profiler(assembly_profiler),
m_range(range),
- m_mutex (Mutex::eMutexTypeNormal),
+ m_mutex (Mutex::eMutexTypeRecursive),
m_unwind_plan_call_site_sp (),
m_unwind_plan_non_call_site_sp (),
m_unwind_plan_fast_sp (),
@@ -68,7 +66,7 @@ FuncUnwinders::GetUnwindPlanAtCallSite (int current_offset)
// if (best_unwind_plan == NULL)
// best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
Mutex::Locker locker (m_mutex);
- if (m_tried_unwind_at_call_site == false && m_unwind_plan_call_site_sp.get() == NULL)
+ if (m_tried_unwind_at_call_site == false && m_unwind_plan_call_site_sp.get() == nullptr)
{
m_tried_unwind_at_call_site = true;
// We have cases (e.g. with _sigtramp on Mac OS X) where the hand-written eh_frame unwind info for a
@@ -96,7 +94,7 @@ FuncUnwinders::GetUnwindPlanAtCallSite (int current_offset)
}
UnwindPlanSP
-FuncUnwinders::GetUnwindPlanAtNonCallSite (Thread& thread)
+FuncUnwinders::GetUnwindPlanAtNonCallSite (Target& target, Thread& thread, int current_offset)
{
// Lock the mutex to ensure we can always give out the most appropriate
// information. We want to make sure if someone requests an unwind
@@ -111,13 +109,29 @@ FuncUnwinders::GetUnwindPlanAtNonCallSite (Thread& thread)
// if (best_unwind_plan == NULL)
// best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
Mutex::Locker locker (m_mutex);
- if (m_tried_unwind_at_non_call_site == false && m_unwind_plan_non_call_site_sp.get() == NULL)
+ if (m_tried_unwind_at_non_call_site == false && m_unwind_plan_non_call_site_sp.get() == nullptr)
{
- m_tried_unwind_at_non_call_site = true;
- if (m_assembly_profiler)
+ UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
+ if (assembly_profiler_sp)
{
+ if (target.GetArchitecture().GetCore() == ArchSpec::eCore_x86_32_i386
+ || target.GetArchitecture().GetCore() == ArchSpec::eCore_x86_64_x86_64
+ || target.GetArchitecture().GetCore() == ArchSpec::eCore_x86_64_x86_64h)
+ {
+ // For 0th frame on i386 & x86_64, we fetch eh_frame and try using assembly profiler
+ // to augment it into asynchronous unwind table.
+ GetUnwindPlanAtCallSite(current_offset);
+ if (m_unwind_plan_call_site_sp) {
+ UnwindPlan* plan = new UnwindPlan (*m_unwind_plan_call_site_sp);
+ if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite (m_range, thread, *plan)) {
+ m_unwind_plan_non_call_site_sp.reset (plan);
+ return m_unwind_plan_non_call_site_sp;
+ }
+ }
+ }
+
m_unwind_plan_non_call_site_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
- if (!m_assembly_profiler->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *m_unwind_plan_non_call_site_sp))
+ if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *m_unwind_plan_non_call_site_sp))
m_unwind_plan_non_call_site_sp.reset();
}
}
@@ -140,13 +154,14 @@ FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread)
// if (best_unwind_plan == NULL)
// best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
Mutex::Locker locker (m_mutex);
- if (m_tried_unwind_fast == false && m_unwind_plan_fast_sp.get() == NULL)
+ if (m_tried_unwind_fast == false && m_unwind_plan_fast_sp.get() == nullptr)
{
m_tried_unwind_fast = true;
- if (m_assembly_profiler)
+ UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
+ if (assembly_profiler_sp)
{
m_unwind_plan_fast_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
- if (!m_assembly_profiler->GetFastUnwindPlan (m_range, thread, *m_unwind_plan_fast_sp))
+ if (!assembly_profiler_sp->GetFastUnwindPlan (m_range, thread, *m_unwind_plan_fast_sp))
m_unwind_plan_fast_sp.reset();
}
}
@@ -169,7 +184,7 @@ FuncUnwinders::GetUnwindPlanArchitectureDefault (Thread& thread)
// if (best_unwind_plan == NULL)
// best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
Mutex::Locker locker (m_mutex);
- if (m_tried_unwind_arch_default == false && m_unwind_plan_arch_default_sp.get() == NULL)
+ if (m_tried_unwind_arch_default == false && m_unwind_plan_arch_default_sp.get() == nullptr)
{
m_tried_unwind_arch_default = true;
Address current_pc;
@@ -205,7 +220,7 @@ FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry (Thread& thread)
// if (best_unwind_plan == NULL)
// best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
Mutex::Locker locker (m_mutex);
- if (m_tried_unwind_arch_default_at_func_entry == false && m_unwind_plan_arch_default_at_func_entry_sp.get() == NULL)
+ if (m_tried_unwind_arch_default_at_func_entry == false && m_unwind_plan_arch_default_at_func_entry_sp.get() == nullptr)
{
m_tried_unwind_arch_default_at_func_entry = true;
Address current_pc;
@@ -232,8 +247,10 @@ FuncUnwinders::GetFirstNonPrologueInsn (Target& target)
if (m_first_non_prologue_insn.IsValid())
return m_first_non_prologue_insn;
ExecutionContext exe_ctx (target.shared_from_this(), false);
- if (m_assembly_profiler)
- m_assembly_profiler->FirstNonPrologueInsn (m_range, exe_ctx, m_first_non_prologue_insn);
+ UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
+ if (assembly_profiler_sp)
+ if (assembly_profiler_sp)
+ assembly_profiler_sp->FirstNonPrologueInsn (m_range, exe_ctx, m_first_non_prologue_insn);
return m_first_non_prologue_insn;
}
@@ -252,3 +269,15 @@ FuncUnwinders::InvalidateNonCallSiteUnwindPlan (lldb_private::Thread& thread)
m_unwind_plan_call_site_sp = arch_default;
}
}
+
+lldb::UnwindAssemblySP
+FuncUnwinders::GetUnwindAssemblyProfiler ()
+{
+ UnwindAssemblySP assembly_profiler_sp;
+ ArchSpec arch;
+ if (m_unwind_table.GetArchitecture (arch))
+ {
+ assembly_profiler_sp = UnwindAssembly::FindPlugin (arch);
+ }
+ return assembly_profiler_sp;
+}
diff --git a/source/Symbol/Function.cpp b/source/Symbol/Function.cpp
index e6d6c000bc97..0b7430ad75e3 100644
--- a/source/Symbol/Function.cpp
+++ b/source/Symbol/Function.cpp
@@ -215,7 +215,7 @@ Function::Function
m_prologue_byte_size (0)
{
m_block.SetParentScope(this);
- assert(comp_unit != NULL);
+ assert(comp_unit != nullptr);
}
Function::Function
@@ -239,7 +239,7 @@ Function::Function
m_prologue_byte_size (0)
{
m_block.SetParentScope(this);
- assert(comp_unit != NULL);
+ assert(comp_unit != nullptr);
}
@@ -253,10 +253,10 @@ Function::GetStartLineSourceInfo (FileSpec &source_file, uint32_t &line_no)
line_no = 0;
source_file.Clear();
- if (m_comp_unit == NULL)
+ if (m_comp_unit == nullptr)
return;
- if (m_type != NULL && m_type->GetDeclaration().GetLine() != 0)
+ if (m_type != nullptr && m_type->GetDeclaration().GetLine() != 0)
{
source_file = m_type->GetDeclaration().GetFile();
line_no = m_type->GetDeclaration().GetLine();
@@ -264,11 +264,11 @@ Function::GetStartLineSourceInfo (FileSpec &source_file, uint32_t &line_no)
else
{
LineTable *line_table = m_comp_unit->GetLineTable();
- if (line_table == NULL)
+ if (line_table == nullptr)
return;
LineEntry line_entry;
- if (line_table->FindLineEntryByAddress (GetAddressRange().GetBaseAddress(), line_entry, NULL))
+ if (line_table->FindLineEntryByAddress (GetAddressRange().GetBaseAddress(), line_entry, nullptr))
{
line_no = line_entry.line;
source_file = line_entry.file;
@@ -288,11 +288,11 @@ Function::GetEndLineSourceInfo (FileSpec &source_file, uint32_t &line_no)
scratch_addr.SetOffset (scratch_addr.GetOffset() + GetAddressRange().GetByteSize() - 1);
LineTable *line_table = m_comp_unit->GetLineTable();
- if (line_table == NULL)
+ if (line_table == nullptr)
return;
LineEntry line_entry;
- if (line_table->FindLineEntryByAddress (scratch_addr, line_entry, NULL))
+ if (line_table->FindLineEntryByAddress (scratch_addr, line_entry, nullptr))
{
line_no = line_entry.line;
source_file = line_entry.file;
@@ -354,20 +354,16 @@ Function::GetDescription(Stream *s, lldb::DescriptionLevel level, Target *target
void
Function::Dump(Stream *s, bool show_context) const
{
- s->Printf("%p: ", this);
+ s->Printf("%p: ", static_cast<const void*>(this));
s->Indent();
- *s << "Function" << (const UserID&)*this;
+ *s << "Function" << static_cast<const UserID&>(*this);
m_mangled.Dump(s);
if (m_type)
- {
- s->Printf(", type = %p", m_type);
- }
+ s->Printf(", type = %p", static_cast<void*>(m_type));
else if (m_type_uid != LLDB_INVALID_UID)
- {
s->Printf(", type_uid = 0x%8.8" PRIx64, m_type_uid);
- }
s->EOL();
// Dump the root object
@@ -415,7 +411,7 @@ Function::GetInstructions (const ExecutionContext &exe_ctx,
{
const bool prefer_file_cache = false;
return Disassembler::DisassembleRange (module_sp->GetArchitecture(),
- NULL,
+ nullptr,
flavor,
exe_ctx,
GetAddressRange(),
@@ -471,17 +467,17 @@ Function::GetClangDeclContext()
CalculateSymbolContext (&sc);
if (!sc.module_sp)
- return NULL;
+ return nullptr;
SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor();
if (!sym_vendor)
- return NULL;
+ return nullptr;
SymbolFile *sym_file = sym_vendor->GetSymbolFile();
if (!sym_file)
- return NULL;
+ return nullptr;
return sym_file->GetClangDeclContextForTypeUID (sc, m_uid);
}
@@ -489,24 +485,24 @@ Function::GetClangDeclContext()
Type*
Function::GetType()
{
- if (m_type == NULL)
+ if (m_type == nullptr)
{
SymbolContext sc;
CalculateSymbolContext (&sc);
if (!sc.module_sp)
- return NULL;
+ return nullptr;
SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor();
- if (sym_vendor == NULL)
- return NULL;
+ if (sym_vendor == nullptr)
+ return nullptr;
SymbolFile *sym_file = sym_vendor->GetSymbolFile();
- if (sym_file == NULL)
- return NULL;
+ if (sym_file == nullptr)
+ return nullptr;
m_type = sym_file->ResolveTypeUID(m_type_uid);
}
diff --git a/source/Symbol/LineTable.cpp b/source/Symbol/LineTable.cpp
index a4aa35ddb318..4b4e33b2b0e9 100644
--- a/source/Symbol/LineTable.cpp
+++ b/source/Symbol/LineTable.cpp
@@ -93,16 +93,26 @@ LineTable::AppendLineEntryToSequence
bool is_terminal_entry
)
{
- assert(sequence != NULL);
+ assert(sequence != nullptr);
LineSequenceImpl* seq = reinterpret_cast<LineSequenceImpl*>(sequence);
Entry entry(file_addr, line, column, file_idx, is_start_of_statement, is_start_of_basic_block, is_prologue_end, is_epilogue_begin, is_terminal_entry);
- seq->m_entries.push_back (entry);
+ entry_collection &entries = seq->m_entries;
+ // Replace the last entry if the address is the same, otherwise append it. If we have multiple
+ // line entries at the same address, this indicates illegal DWARF so this "fixes" the line table
+ // to be correct. If not fixed this can cause a line entry's address that when resolved back to
+ // a symbol context, could resolve to a different line entry. We really want a 1 to 1 mapping
+ // here to avoid these kinds of inconsistencies. We will need tor revisit this if the DWARF line
+ // tables are updated to allow multiple entries at the same address legally.
+ if (!entries.empty() && entries.back().file_addr == file_addr)
+ entries.back() = entry;
+ else
+ entries.push_back (entry);
}
void
LineTable::InsertSequence (LineSequence* sequence)
{
- assert(sequence != NULL);
+ assert(sequence != nullptr);
LineSequenceImpl* seq = reinterpret_cast<LineSequenceImpl*>(sequence);
if (seq->m_entries.empty())
return;
@@ -183,7 +193,7 @@ LineTable::GetLineEntryAtIndex(uint32_t idx, LineEntry& line_entry)
bool
LineTable::FindLineEntryByAddress (const Address &so_addr, LineEntry& line_entry, uint32_t *index_ptr)
{
- if (index_ptr != NULL )
+ if (index_ptr != nullptr )
*index_ptr = UINT32_MAX;
bool success = false;
@@ -247,7 +257,7 @@ LineTable::FindLineEntryByAddress (const Address &so_addr, LineEntry& line_entry
{
uint32_t match_idx = std::distance (begin_pos, pos);
success = ConvertEntryAtIndexToLineEntry(match_idx, line_entry);
- if (index_ptr != NULL && success)
+ if (index_ptr != nullptr && success)
*index_ptr = match_idx;
}
}
@@ -493,8 +503,8 @@ LineTable::LinkLineTable (const FileRangeMap &file_range_map)
LineSequenceImpl sequence;
const size_t count = m_entries.size();
LineEntry line_entry;
- const FileRangeMap::Entry *file_range_entry = NULL;
- const FileRangeMap::Entry *prev_file_range_entry = NULL;
+ const FileRangeMap::Entry *file_range_entry = nullptr;
+ const FileRangeMap::Entry *prev_file_range_entry = nullptr;
lldb::addr_t prev_file_addr = LLDB_INVALID_ADDRESS;
bool prev_entry_was_linked = false;
bool range_changed = false;
@@ -504,7 +514,7 @@ LineTable::LinkLineTable (const FileRangeMap &file_range_map)
const bool end_sequence = entry.is_terminal_entry;
const lldb::addr_t lookup_file_addr = entry.file_addr - (end_sequence ? 1 : 0);
- if (file_range_entry == NULL || !file_range_entry->Contains(lookup_file_addr))
+ if (file_range_entry == nullptr || !file_range_entry->Contains(lookup_file_addr))
{
prev_file_range_entry = file_range_entry;
file_range_entry = file_range_map.FindEntryThatContains(lookup_file_addr);
@@ -573,13 +583,13 @@ LineTable::LinkLineTable (const FileRangeMap &file_range_map)
}
else
{
- prev_entry_was_linked = file_range_entry != NULL;
+ prev_entry_was_linked = file_range_entry != nullptr;
}
prev_file_addr = entry.file_addr;
range_changed = false;
}
if (line_table_ap->m_entries.empty())
- return NULL;
+ return nullptr;
return line_table_ap.release();
}
diff --git a/source/Symbol/ObjectFile.cpp b/source/Symbol/ObjectFile.cpp
index ec69c9dd1e15..11b540071208 100644
--- a/source/Symbol/ObjectFile.cpp
+++ b/source/Symbol/ObjectFile.cpp
@@ -42,7 +42,9 @@ ObjectFile::FindPlugin (const lldb::ModuleSP &module_sp,
Timer scoped_timer (__PRETTY_FUNCTION__,
"ObjectFile::FindPlugin (module = %s, file = %p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")",
module_sp->GetFileSpec().GetPath().c_str(),
- file, (uint64_t) file_offset, (uint64_t) file_size);
+ static_cast<const void*>(file),
+ static_cast<uint64_t>(file_offset),
+ static_cast<uint64_t>(file_size));
if (file)
{
FileSpec archive_file;
@@ -57,13 +59,13 @@ ObjectFile::FindPlugin (const lldb::ModuleSP &module_sp,
// first
if (file_exists && module_sp->GetObjectName())
{
- for (uint32_t idx = 0; (create_object_container_callback = PluginManager::GetObjectContainerCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ for (uint32_t idx = 0; (create_object_container_callback = PluginManager::GetObjectContainerCreateCallbackAtIndex(idx)) != nullptr; ++idx)
{
std::unique_ptr<ObjectContainer> object_container_ap(create_object_container_callback(module_sp, data_sp, data_offset, file, file_offset, file_size));
-
+
if (object_container_ap.get())
object_file_sp = object_container_ap->GetObjectFile(file);
-
+
if (object_file_sp.get())
return object_file_sp;
}
@@ -99,13 +101,13 @@ ObjectFile::FindPlugin (const lldb::ModuleSP &module_sp,
// from the container plugins since we had a name. Also, don't read
// ANY data in case there is data cached in the container plug-ins
// (like BSD archives caching the contained objects within an file).
- for (uint32_t idx = 0; (create_object_container_callback = PluginManager::GetObjectContainerCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ for (uint32_t idx = 0; (create_object_container_callback = PluginManager::GetObjectContainerCreateCallbackAtIndex(idx)) != nullptr; ++idx)
{
std::unique_ptr<ObjectContainer> object_container_ap(create_object_container_callback(module_sp, data_sp, data_offset, file, file_offset, file_size));
-
+
if (object_container_ap.get())
object_file_sp = object_container_ap->GetObjectFile(file);
-
+
if (object_file_sp.get())
return object_file_sp;
}
@@ -121,7 +123,7 @@ ObjectFile::FindPlugin (const lldb::ModuleSP &module_sp,
// Check if this is a normal object file by iterating through
// all object file plugin instances.
ObjectFileCreateInstance create_object_file_callback;
- for (uint32_t idx = 0; (create_object_file_callback = PluginManager::GetObjectFileCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ for (uint32_t idx = 0; (create_object_file_callback = PluginManager::GetObjectFileCreateCallbackAtIndex(idx)) != nullptr; ++idx)
{
object_file_sp.reset (create_object_file_callback(module_sp, data_sp, data_offset, file, file_offset, file_size));
if (object_file_sp.get())
@@ -131,7 +133,7 @@ ObjectFile::FindPlugin (const lldb::ModuleSP &module_sp,
// Check if this is a object container by iterating through
// all object container plugin instances and then trying to get
// an object file from the container.
- for (uint32_t idx = 0; (create_object_container_callback = PluginManager::GetObjectContainerCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ for (uint32_t idx = 0; (create_object_container_callback = PluginManager::GetObjectContainerCreateCallbackAtIndex(idx)) != nullptr; ++idx)
{
std::unique_ptr<ObjectContainer> object_container_ap(create_object_container_callback(module_sp, data_sp, data_offset, file, file_offset, file_size));
@@ -157,26 +159,26 @@ ObjectFile::FindPlugin (const lldb::ModuleSP &module_sp,
DataBufferSP &data_sp)
{
ObjectFileSP object_file_sp;
-
+
if (module_sp)
{
Timer scoped_timer (__PRETTY_FUNCTION__,
"ObjectFile::FindPlugin (module = %s, process = %p, header_addr = 0x%" PRIx64 ")",
module_sp->GetFileSpec().GetPath().c_str(),
- process_sp.get(), header_addr);
+ static_cast<void*>(process_sp.get()), header_addr);
uint32_t idx;
-
+
// Check if this is a normal object file by iterating through
// all object file plugin instances.
ObjectFileCreateMemoryInstance create_callback;
- for (idx = 0; (create_callback = PluginManager::GetObjectFileCreateMemoryCallbackAtIndex(idx)) != NULL; ++idx)
+ for (idx = 0; (create_callback = PluginManager::GetObjectFileCreateMemoryCallbackAtIndex(idx)) != nullptr; ++idx)
{
object_file_sp.reset (create_callback(module_sp, data_sp, process_sp, header_addr));
if (object_file_sp.get())
return object_file_sp;
}
-
}
+
// We didn't find it, so clear our shared pointer in case it
// contains anything and return an empty shared pointer
object_file_sp.reset();
@@ -220,14 +222,14 @@ ObjectFile::GetModuleSpecifications (const lldb_private::FileSpec& file,
ObjectFileGetModuleSpecifications callback;
uint32_t i;
// Try the ObjectFile plug-ins
- for (i = 0; (callback = PluginManager::GetObjectFileGetModuleSpecificationsCallbackAtIndex(i)) != NULL; ++i)
+ for (i = 0; (callback = PluginManager::GetObjectFileGetModuleSpecificationsCallbackAtIndex(i)) != nullptr; ++i)
{
if (callback (file, data_sp, data_offset, file_offset, file_size, specs) > 0)
return specs.GetSize() - initial_count;
}
// Try the ObjectContainer plug-ins
- for (i = 0; (callback = PluginManager::GetObjectContainerGetModuleSpecificationsCallbackAtIndex(i)) != NULL; ++i)
+ for (i = 0; (callback = PluginManager::GetObjectContainerGetModuleSpecificationsCallbackAtIndex(i)) != nullptr; ++i)
{
if (callback (file, data_sp, data_offset, file_offset, file_size, specs) > 0)
return specs.GetSize() - initial_count;
@@ -239,7 +241,7 @@ ObjectFile::ObjectFile (const lldb::ModuleSP &module_sp,
const FileSpec *file_spec_ptr,
lldb::offset_t file_offset,
lldb::offset_t length,
- lldb::DataBufferSP& data_sp,
+ const lldb::DataBufferSP& data_sp,
lldb::offset_t data_offset
) :
ModuleChild (module_sp),
@@ -261,27 +263,12 @@ ObjectFile::ObjectFile (const lldb::ModuleSP &module_sp,
m_data.SetData (data_sp, data_offset, length);
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- {
- if (m_file)
- {
- log->Printf ("%p ObjectFile::ObjectFile() module = %p (%s), file = %s, file_offset = 0x%8.8" PRIx64 ", size = %" PRIu64,
- this,
- module_sp.get(),
- module_sp->GetSpecificationDescription().c_str(),
- m_file.GetPath().c_str(),
- m_file_offset,
- m_length);
- }
- else
- {
- log->Printf ("%p ObjectFile::ObjectFile() module = %p (%s), file = <NULL>, file_offset = 0x%8.8" PRIx64 ", size = %" PRIu64,
- this,
- module_sp.get(),
- module_sp->GetSpecificationDescription().c_str(),
- m_file_offset,
- m_length);
- }
- }
+ log->Printf ("%p ObjectFile::ObjectFile() module = %p (%s), file = %s, file_offset = 0x%8.8" PRIx64 ", size = %" PRIu64,
+ static_cast<void*>(this),
+ static_cast<void*>(module_sp.get()),
+ module_sp->GetSpecificationDescription().c_str(),
+ m_file ? m_file.GetPath().c_str() : "<NULL>",
+ m_file_offset, m_length);
}
@@ -306,14 +293,11 @@ ObjectFile::ObjectFile (const lldb::ModuleSP &module_sp,
m_data.SetData (header_data_sp, 0, header_data_sp->GetByteSize());
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- {
log->Printf ("%p ObjectFile::ObjectFile() module = %p (%s), process = %p, header_addr = 0x%" PRIx64,
- this,
- module_sp.get(),
+ static_cast<void*>(this),
+ static_cast<void*>(module_sp.get()),
module_sp->GetSpecificationDescription().c_str(),
- process_sp.get(),
- m_memory_addr);
- }
+ static_cast<void*>(process_sp.get()), m_memory_addr);
}
@@ -321,7 +305,8 @@ ObjectFile::~ObjectFile()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p ObjectFile::~ObjectFile ()\n", this);
+ log->Printf ("%p ObjectFile::~ObjectFile ()\n",
+ static_cast<void*>(this));
}
bool
@@ -350,9 +335,12 @@ ObjectFile::GetAddressClass (addr_t file_addr)
const SectionType section_type = section_sp->GetType();
switch (section_type)
{
- case eSectionTypeInvalid: return eAddressClassUnknown;
- case eSectionTypeCode: return eAddressClassCode;
- case eSectionTypeContainer: return eAddressClassUnknown;
+ case eSectionTypeInvalid:
+ return eAddressClassUnknown;
+ case eSectionTypeCode:
+ return eAddressClassCode;
+ case eSectionTypeContainer:
+ return eAddressClassUnknown;
case eSectionTypeData:
case eSectionTypeDataCString:
case eSectionTypeDataCStringPointers:
@@ -382,16 +370,18 @@ ObjectFile::GetAddressClass (addr_t file_addr)
case eSectionTypeDWARFAppleNamespaces:
case eSectionTypeDWARFAppleObjC:
return eAddressClassDebug;
- case eSectionTypeEHFrame: return eAddressClassRuntime;
+ case eSectionTypeEHFrame:
+ return eAddressClassRuntime;
case eSectionTypeELFSymbolTable:
case eSectionTypeELFDynamicSymbols:
case eSectionTypeELFRelocationEntries:
case eSectionTypeELFDynamicLinkInfo:
- case eSectionTypeOther: return eAddressClassUnknown;
+ case eSectionTypeOther:
+ return eAddressClassUnknown;
}
}
}
-
+
const SymbolType symbol_type = symbol->GetType();
switch (symbol_type)
{
@@ -449,7 +439,7 @@ ObjectFile::ReadMemory (const ProcessSP &process_sp, lldb::addr_t addr, size_t b
}
size_t
-ObjectFile::GetData (off_t offset, size_t length, DataExtractor &data) const
+ObjectFile::GetData (lldb::offset_t offset, size_t length, DataExtractor &data) const
{
// The entire file has already been mmap'ed into m_data, so just copy from there
// as the back mmap buffer will be shared with shared pointers.
@@ -457,7 +447,7 @@ ObjectFile::GetData (off_t offset, size_t length, DataExtractor &data) const
}
size_t
-ObjectFile::CopyData (off_t offset, size_t length, void *dst) const
+ObjectFile::CopyData (lldb::offset_t offset, size_t length, void *dst) const
{
// The entire file has already been mmap'ed into m_data, so just copy from there
// Note that the data remains in target byte order.
@@ -466,7 +456,7 @@ ObjectFile::CopyData (off_t offset, size_t length, void *dst) const
size_t
-ObjectFile::ReadSectionData (const Section *section, off_t section_offset, void *dst, size_t dst_len) const
+ObjectFile::ReadSectionData (const Section *section, lldb::offset_t section_offset, void *dst, size_t dst_len) const
{
// If some other objectfile owns this data, pass this to them.
if (section->GetObjectFile() != this)
@@ -485,11 +475,11 @@ ObjectFile::ReadSectionData (const Section *section, off_t section_offset, void
}
else
{
- const uint64_t section_file_size = section->GetFileSize();
+ const lldb::offset_t section_file_size = section->GetFileSize();
if (section_offset < section_file_size)
{
- const uint64_t section_bytes_left = section_file_size - section_offset;
- uint64_t section_dst_len = dst_len;
+ const size_t section_bytes_left = section_file_size - section_offset;
+ size_t section_dst_len = dst_len;
if (section_dst_len > section_bytes_left)
section_dst_len = section_bytes_left;
return CopyData (section->GetFileOffset() + section_offset, section_dst_len, dst);
@@ -601,11 +591,9 @@ ObjectFile::ClearSymtab ()
lldb_private::Mutex::Locker locker(module_sp->GetMutex());
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- {
log->Printf ("%p ObjectFile::ClearSymtab () symtab = %p",
- this,
- m_symtab_ap.get());
- }
+ static_cast<void*>(this),
+ static_cast<void*>(m_symtab_ap.get()));
m_symtab_ap.reset();
}
}
@@ -613,11 +601,14 @@ ObjectFile::ClearSymtab ()
SectionList *
ObjectFile::GetSectionList()
{
- if (m_sections_ap.get() == NULL)
+ if (m_sections_ap.get() == nullptr)
{
ModuleSP module_sp(GetModule());
if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
CreateSections(*module_sp->GetUnifiedSectionList());
+ }
}
return m_sections_ap.get();
}
diff --git a/source/Symbol/Symbol.cpp b/source/Symbol/Symbol.cpp
index 6311a329739e..880519955277 100644
--- a/source/Symbol/Symbol.cpp
+++ b/source/Symbol/Symbol.cpp
@@ -174,7 +174,7 @@ Symbol::Clear()
bool
Symbol::ValueIsAddress() const
{
- return m_addr_range.GetBaseAddress().GetSection().get() != NULL;
+ return m_addr_range.GetBaseAddress().GetSection().get() != nullptr;
}
ConstString
@@ -312,7 +312,7 @@ Symbol::Dump(Stream *s, Target *target, uint32_t index) const
if (ValueIsAddress())
{
- if (!m_addr_range.GetBaseAddress().Dump(s, NULL, Address::DumpStyleFileAddress))
+ if (!m_addr_range.GetBaseAddress().Dump(s, nullptr, Address::DumpStyleFileAddress))
s->Printf("%*s", 18, "");
s->PutChar(' ');
@@ -536,49 +536,129 @@ Symbol::GetByteSize () const
return m_addr_range.GetByteSize();
}
+
Symbol *
-Symbol::ResolveReExportedSymbol (Target &target)
+Symbol::ResolveReExportedSymbolInModuleSpec (Target &target,
+ ConstString &reexport_name,
+ ModuleSpec &module_spec,
+ ModuleList &seen_modules) const
{
- ConstString reexport_name (GetReExportedSymbolName());
- if (reexport_name)
+ ModuleSP module_sp;
+ if (module_spec.GetFileSpec())
{
- ModuleSpec module_spec;
- ModuleSP module_sp;
- module_spec.GetFileSpec() = GetReExportedSymbolSharedLibrary();
- if (module_spec.GetFileSpec())
+ // Try searching for the module file spec first using the full path
+ module_sp = target.GetImages().FindFirstModule(module_spec);
+ if (!module_sp)
{
- // Try searching for the module file spec first using the full path
+ // Next try and find the module by basename in case environment
+ // variables or other runtime trickery causes shared libraries
+ // to be loaded from alternate paths
+ module_spec.GetFileSpec().GetDirectory().Clear();
module_sp = target.GetImages().FindFirstModule(module_spec);
- if (!module_sp)
- {
- // Next try and find the module by basename in case environment
- // variables or other runtime trickery causes shared libraries
- // to be loaded from alternate paths
- module_spec.GetFileSpec().GetDirectory().Clear();
- module_sp = target.GetImages().FindFirstModule(module_spec);
- }
}
+ }
+
+ if (module_sp)
+ {
+ // There should not be cycles in the reexport list, but we don't want to crash if there are so make sure
+ // we haven't seen this before:
+ if (!seen_modules.AppendIfNeeded(module_sp))
+ return nullptr;
- if (module_sp)
+ lldb_private::SymbolContextList sc_list;
+ module_sp->FindSymbolsWithNameAndType(reexport_name, eSymbolTypeAny, sc_list);
+ const size_t num_scs = sc_list.GetSize();
+ if (num_scs > 0)
{
- lldb_private::SymbolContextList sc_list;
- module_sp->FindSymbolsWithNameAndType(reexport_name, eSymbolTypeAny, sc_list);
- const size_t num_scs = sc_list.GetSize();
- if (num_scs > 0)
+ for (size_t i=0; i<num_scs; ++i)
{
- for (size_t i=0; i<num_scs; ++i)
+ lldb_private::SymbolContext sc;
+ if (sc_list.GetContextAtIndex(i, sc))
{
- lldb_private::SymbolContext sc;
- if (sc_list.GetContextAtIndex(i, sc))
- {
- if (sc.symbol->IsExternal())
- return sc.symbol;
- }
+ if (sc.symbol->IsExternal())
+ return sc.symbol;
}
}
}
+ // If we didn't find the symbol in this module, it may be because this module re-exports some
+ // whole other library. We have to search those as well:
+ seen_modules.Append(module_sp);
+
+ FileSpecList reexported_libraries = module_sp->GetObjectFile()->GetReExportedLibraries();
+ size_t num_reexported_libraries = reexported_libraries.GetSize();
+ for (size_t idx = 0; idx < num_reexported_libraries; idx++)
+ {
+ ModuleSpec reexported_module_spec;
+ reexported_module_spec.GetFileSpec() = reexported_libraries.GetFileSpecAtIndex(idx);
+ Symbol *result_symbol = ResolveReExportedSymbolInModuleSpec(target,
+ reexport_name,
+ reexported_module_spec,
+ seen_modules);
+ if (result_symbol)
+ return result_symbol;
+ }
+ }
+ return nullptr;
+}
+
+Symbol *
+Symbol::ResolveReExportedSymbol (Target &target) const
+{
+ ConstString reexport_name (GetReExportedSymbolName());
+ if (reexport_name)
+ {
+ ModuleSpec module_spec;
+ ModuleList seen_modules;
+ module_spec.GetFileSpec() = GetReExportedSymbolSharedLibrary();
+ if (module_spec.GetFileSpec())
+ {
+ return ResolveReExportedSymbolInModuleSpec(target, reexport_name, module_spec, seen_modules);
+ }
+ }
+ return nullptr;
+}
+
+lldb::addr_t
+Symbol::ResolveCallableAddress(Target &target) const
+{
+ if (GetType() == lldb::eSymbolTypeUndefined)
+ return LLDB_INVALID_ADDRESS;
+
+ Address func_so_addr;
+
+ bool is_indirect;
+ if (GetType() == eSymbolTypeReExported)
+ {
+ Symbol *reexported_symbol = ResolveReExportedSymbol(target);
+ if (reexported_symbol)
+ {
+ func_so_addr = reexported_symbol->GetAddress();
+ is_indirect = reexported_symbol->IsIndirect();
+ }
}
- return NULL;
+ else
+ {
+ func_so_addr = GetAddress();
+ is_indirect = IsIndirect();
+ }
+
+ if (func_so_addr.IsValid())
+ {
+ if (!target.GetProcessSP() && is_indirect)
+ {
+ // can't resolve indirect symbols without calling a function...
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ lldb::addr_t load_addr = func_so_addr.GetCallableLoadAddress (&target, is_indirect);
+
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ return load_addr;
+ }
+ }
+
+ return LLDB_INVALID_ADDRESS;
}
@@ -592,7 +672,7 @@ Symbol::GetInstructions (const ExecutionContext &exe_ctx,
{
const bool prefer_file_cache = false;
return Disassembler::DisassembleRange (module_sp->GetArchitecture(),
- NULL,
+ nullptr,
flavor,
exe_ctx,
m_addr_range,
diff --git a/source/Symbol/SymbolContext.cpp b/source/Symbol/SymbolContext.cpp
index f1e581f71613..0e390dd08c5f 100644
--- a/source/Symbol/SymbolContext.cpp
+++ b/source/Symbol/SymbolContext.cpp
@@ -29,11 +29,11 @@ using namespace lldb_private;
SymbolContext::SymbolContext() :
target_sp (),
module_sp (),
- comp_unit (NULL),
- function (NULL),
- block (NULL),
+ comp_unit (nullptr),
+ function (nullptr),
+ block (nullptr),
line_entry (),
- symbol (NULL)
+ symbol (nullptr)
{
}
@@ -78,11 +78,11 @@ SymbolContext::SymbolContext(const SymbolContext& rhs) :
SymbolContext::SymbolContext (SymbolContextScope *sc_scope) :
target_sp (),
module_sp (),
- comp_unit (NULL),
- function (NULL),
- block (NULL),
+ comp_unit (nullptr),
+ function (nullptr),
+ block (nullptr),
line_entry (),
- symbol (NULL)
+ symbol (nullptr)
{
sc_scope->CalculateSymbolContext (this);
}
@@ -113,11 +113,11 @@ SymbolContext::Clear(bool clear_target)
if (clear_target)
target_sp.reset();
module_sp.reset();
- comp_unit = NULL;
- function = NULL;
- block = NULL;
+ comp_unit = nullptr;
+ function = nullptr;
+ block = nullptr;
line_entry.Clear();
- symbol = NULL;
+ symbol = nullptr;
}
bool
@@ -142,7 +142,7 @@ SymbolContext::DumpStopContext
dumped_something = true;
}
- if (function != NULL)
+ if (function != nullptr)
{
SymbolContext inline_parent_sc;
Address inline_parent_addr;
@@ -202,7 +202,7 @@ SymbolContext::DumpStopContext
}
}
}
- else if (symbol != NULL)
+ else if (symbol != nullptr)
{
if (symbol->GetMangled().GetName())
{
@@ -243,14 +243,14 @@ SymbolContext::GetDescription(Stream *s, lldb::DescriptionLevel level, Target *t
s->EOL();
}
- if (comp_unit != NULL)
+ if (comp_unit != nullptr)
{
s->Indent("CompileUnit: ");
comp_unit->GetDescription (s, level);
s->EOL();
}
- if (function != NULL)
+ if (function != nullptr)
{
s->Indent(" Function: ");
function->GetDescription (s, level, target);
@@ -265,7 +265,7 @@ SymbolContext::GetDescription(Stream *s, lldb::DescriptionLevel level, Target *t
}
}
- if (block != NULL)
+ if (block != nullptr)
{
std::vector<Block *> blocks;
blocks.push_back (block);
@@ -297,7 +297,7 @@ SymbolContext::GetDescription(Stream *s, lldb::DescriptionLevel level, Target *t
s->EOL();
}
- if (symbol != NULL)
+ if (symbol != nullptr)
{
s->Indent(" Symbol: ");
symbol->GetDescription(s, level, target);
@@ -335,12 +335,12 @@ SymbolContext::Dump(Stream *s, Target *target) const
s->EOL();
s->Indent();
*s << "CompileUnit = " << (void *)comp_unit;
- if (comp_unit != NULL)
+ if (comp_unit != nullptr)
*s << " {0x" << comp_unit->GetID() << "} " << *(static_cast<FileSpec*> (comp_unit));
s->EOL();
s->Indent();
*s << "Function = " << (void *)function;
- if (function != NULL)
+ if (function != nullptr)
{
*s << " {0x" << function->GetID() << "} " << function->GetType()->GetName() << ", address-range = ";
function->GetAddressRange().Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress);
@@ -356,7 +356,7 @@ SymbolContext::Dump(Stream *s, Target *target) const
s->EOL();
s->Indent();
*s << "Block = " << (void *)block;
- if (block != NULL)
+ if (block != nullptr)
*s << " {0x" << block->GetID() << '}';
// Dump the block and pass it a negative depth to we print all the parent blocks
//if (block != NULL)
@@ -368,7 +368,7 @@ SymbolContext::Dump(Stream *s, Target *target) const
s->EOL();
s->Indent();
*s << "Symbol = " << (void *)symbol;
- if (symbol != NULL && symbol->GetMangled())
+ if (symbol != nullptr && symbol->GetMangled())
*s << ' ' << symbol->GetMangled().GetName().AsCString();
s->EOL();
s->IndentLess();
@@ -409,7 +409,7 @@ SymbolContext::GetAddressRange (uint32_t scope,
return true;
}
- if ((scope & eSymbolContextBlock) && (block != NULL))
+ if ((scope & eSymbolContextBlock) && (block != nullptr))
{
if (use_inline_block_range)
{
@@ -423,7 +423,7 @@ SymbolContext::GetAddressRange (uint32_t scope,
}
}
- if ((scope & eSymbolContextFunction) && (function != NULL))
+ if ((scope & eSymbolContextFunction) && (function != nullptr))
{
if (range_idx == 0)
{
@@ -432,7 +432,7 @@ SymbolContext::GetAddressRange (uint32_t scope,
}
}
- if ((scope & eSymbolContextSymbol) && (symbol != NULL))
+ if ((scope & eSymbolContextSymbol) && (symbol != nullptr))
{
if (range_idx == 0)
{
@@ -562,7 +562,7 @@ SymbolContext::GetFunctionBlock ()
// the function itself.
return &function->GetBlock(true);
}
- return NULL;
+ return nullptr;
}
bool
@@ -777,7 +777,7 @@ SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc)
{
if (sc.module_sp)
{
- if (m_module_sp.get() != NULL)
+ if (m_module_sp.get() != nullptr)
{
if (m_module_sp.get() != sc.module_sp.get())
return false;
@@ -795,15 +795,15 @@ SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc)
if (m_file_spec_ap.get())
{
// If we don't have a block or a comp_unit, then we aren't going to match a source file.
- if (sc.block == NULL && sc.comp_unit == NULL)
+ if (sc.block == nullptr && sc.comp_unit == nullptr)
return false;
// Check if the block is present, and if so is it inlined:
bool was_inlined = false;
- if (sc.block != NULL)
+ if (sc.block != nullptr)
{
const InlineFunctionInfo *inline_info = sc.block->GetInlinedFunctionInfo();
- if (inline_info != NULL)
+ if (inline_info != nullptr)
{
was_inlined = true;
if (!FileSpec::Equal (inline_info->GetDeclaration().GetFile(), *(m_file_spec_ap.get()), false))
@@ -812,7 +812,7 @@ SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc)
}
// Next check the comp unit, but only if the SymbolContext was not inlined.
- if (!was_inlined && sc.comp_unit != NULL)
+ if (!was_inlined && sc.comp_unit != nullptr)
{
if (!FileSpec::Equal (*(sc.comp_unit), *(m_file_spec_ap.get()), false))
return false;
@@ -832,10 +832,10 @@ SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc)
bool was_inlined = false;
ConstString func_name(m_function_spec.c_str());
- if (sc.block != NULL)
+ if (sc.block != nullptr)
{
const InlineFunctionInfo *inline_info = sc.block->GetInlinedFunctionInfo();
- if (inline_info != NULL)
+ if (inline_info != nullptr)
{
was_inlined = true;
const Mangled &name = inline_info->GetMangled();
@@ -846,12 +846,12 @@ SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc)
// If it wasn't inlined, check the name in the function or symbol:
if (!was_inlined)
{
- if (sc.function != NULL)
+ if (sc.function != nullptr)
{
if (!sc.function->GetMangled().NameMatches(func_name))
return false;
}
- else if (sc.symbol != NULL)
+ else if (sc.symbol != nullptr)
{
if (!sc.symbol->GetMangled().NameMatches(func_name))
return false;
@@ -873,7 +873,7 @@ SymbolContextSpecifier::AddressMatches(lldb::addr_t addr)
}
else
{
- Address match_address (addr, NULL);
+ Address match_address (addr, nullptr);
SymbolContext sc;
m_target_sp->GetImages().ResolveSymbolContextForAddress(match_address, eSymbolContextEverything, sc);
return SymbolContextMatches(sc);
@@ -903,22 +903,22 @@ SymbolContextSpecifier::GetDescription (Stream *s, lldb::DescriptionLevel level)
s->Printf ("Module: %s\n", m_module_spec.c_str());
}
- if (m_type == eFileSpecified && m_file_spec_ap.get() != NULL)
+ if (m_type == eFileSpecified && m_file_spec_ap.get() != nullptr)
{
m_file_spec_ap->GetPath (path_str, PATH_MAX);
s->Indent();
s->Printf ("File: %s", path_str);
if (m_type == eLineStartSpecified)
{
- s->Printf (" from line %zu", m_start_line);
+ s->Printf (" from line %" PRIu64 "", (uint64_t)m_start_line);
if (m_type == eLineEndSpecified)
- s->Printf ("to line %zu", m_end_line);
+ s->Printf ("to line %" PRIu64 "", (uint64_t)m_end_line);
else
s->Printf ("to end");
}
else if (m_type == eLineEndSpecified)
{
- s->Printf (" from start to line %zu", m_end_line);
+ s->Printf (" from start to line %" PRIu64 "", (uint64_t)m_end_line);
}
s->Printf (".\n");
}
@@ -926,16 +926,16 @@ SymbolContextSpecifier::GetDescription (Stream *s, lldb::DescriptionLevel level)
if (m_type == eLineStartSpecified)
{
s->Indent();
- s->Printf ("From line %zu", m_start_line);
+ s->Printf ("From line %" PRIu64 "", (uint64_t)m_start_line);
if (m_type == eLineEndSpecified)
- s->Printf ("to line %zu", m_end_line);
+ s->Printf ("to line %" PRIu64 "", (uint64_t)m_end_line);
else
s->Printf ("to end");
s->Printf (".\n");
}
else if (m_type == eLineEndSpecified)
{
- s->Printf ("From start to line %zu.\n", m_end_line);
+ s->Printf ("From start to line %" PRIu64 ".\n", (uint64_t)m_end_line);
}
if (m_type == eFunctionSpecified)
@@ -950,7 +950,7 @@ SymbolContextSpecifier::GetDescription (Stream *s, lldb::DescriptionLevel level)
s->Printf ("Class name: %s.\n", m_class_name.c_str());
}
- if (m_type == eAddressRangeSpecified && m_address_range_ap.get() != NULL)
+ if (m_type == eAddressRangeSpecified && m_address_range_ap.get() != nullptr)
{
s->Indent();
s->PutCString ("Address range: ");
@@ -1013,10 +1013,10 @@ SymbolContextList::AppendIfUnique (const SymbolContext& sc, bool merge_symbol_in
return false;
}
if (merge_symbol_into_function
- && sc.symbol != NULL
- && sc.comp_unit == NULL
- && sc.function == NULL
- && sc.block == NULL
+ && sc.symbol != nullptr
+ && sc.comp_unit == nullptr
+ && sc.function == nullptr
+ && sc.block == nullptr
&& sc.line_entry.IsValid() == false)
{
if (sc.symbol->ValueIsAddress())
@@ -1034,7 +1034,7 @@ SymbolContextList::AppendIfUnique (const SymbolContext& sc, bool merge_symbol_in
// Do we already have a function with this symbol?
if (pos->symbol == sc.symbol)
return false;
- if (pos->symbol == NULL)
+ if (pos->symbol == nullptr)
{
pos->symbol = sc.symbol;
return false;
@@ -1053,10 +1053,10 @@ SymbolContextList::MergeSymbolContextIntoFunctionContext (const SymbolContext& s
uint32_t start_idx,
uint32_t stop_idx)
{
- if (symbol_sc.symbol != NULL
- && symbol_sc.comp_unit == NULL
- && symbol_sc.function == NULL
- && symbol_sc.block == NULL
+ if (symbol_sc.symbol != nullptr
+ && symbol_sc.comp_unit == nullptr
+ && symbol_sc.function == nullptr
+ && symbol_sc.block == nullptr
&& symbol_sc.line_entry.IsValid() == false)
{
if (symbol_sc.symbol->ValueIsAddress())
@@ -1077,7 +1077,7 @@ SymbolContextList::MergeSymbolContextIntoFunctionContext (const SymbolContext& s
if (function_sc.symbol == symbol_sc.symbol)
return true; // Already have a symbol context with this symbol, return true
- if (function_sc.symbol == NULL)
+ if (function_sc.symbol == nullptr)
{
// We successfully merged this symbol into an existing symbol context
m_symbol_contexts[i].symbol = symbol_sc.symbol;
diff --git a/source/Symbol/SymbolFile.cpp b/source/Symbol/SymbolFile.cpp
index 412c4600c9f7..a5b138bb52af 100644
--- a/source/Symbol/SymbolFile.cpp
+++ b/source/Symbol/SymbolFile.cpp
@@ -22,7 +22,7 @@ SymbolFile*
SymbolFile::FindPlugin (ObjectFile* obj_file)
{
std::unique_ptr<SymbolFile> best_symfile_ap;
- if (obj_file != NULL)
+ if (obj_file != nullptr)
{
// We need to test the abilities of this section list. So create what it would
@@ -46,7 +46,7 @@ SymbolFile::FindPlugin (ObjectFile* obj_file)
uint32_t best_symfile_abilities = 0;
SymbolFileCreateInstance create_callback;
- for (uint32_t idx = 0; (create_callback = PluginManager::GetSymbolFileCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetSymbolFileCreateCallbackAtIndex(idx)) != nullptr; ++idx)
{
std::unique_ptr<SymbolFile> curr_symfile_ap(create_callback(obj_file));
@@ -79,7 +79,7 @@ SymbolFile::GetTypeList ()
{
if (m_obj_file)
return m_obj_file->GetModule()->GetTypeList();
- return NULL;
+ return nullptr;
}
lldb_private::ClangASTContext &
diff --git a/source/Symbol/SymbolVendor.cpp b/source/Symbol/SymbolVendor.cpp
index b51ac5a550fb..a3f4104016e5 100644
--- a/source/Symbol/SymbolVendor.cpp
+++ b/source/Symbol/SymbolVendor.cpp
@@ -37,7 +37,7 @@ SymbolVendor::FindPlugin (const lldb::ModuleSP &module_sp, lldb_private::Stream
std::unique_ptr<SymbolVendor> instance_ap;
SymbolVendorCreateInstance create_callback;
- for (size_t idx = 0; (create_callback = PluginManager::GetSymbolVendorCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ for (size_t idx = 0; (create_callback = PluginManager::GetSymbolVendorCreateCallbackAtIndex(idx)) != nullptr; ++idx)
{
instance_ap.reset(create_callback(module_sp, feedback_strm));
@@ -109,7 +109,7 @@ SymbolVendor::SetCompileUnitAtIndex (size_t idx, const CompUnitSP &cu_sp)
// unit once, so if this assertion fails, we need to make sure that
// we don't have a race condition, or have a second parse of the same
// compile unit.
- assert(m_compile_units[idx].get() == NULL);
+ assert(m_compile_units[idx].get() == nullptr);
m_compile_units[idx] = cu_sp;
return true;
}
@@ -247,7 +247,7 @@ SymbolVendor::ResolveTypeUID(lldb::user_id_t type_uid)
if (m_sym_file_ap.get())
return m_sym_file_ap->ResolveTypeUID(type_uid);
}
- return NULL;
+ return nullptr;
}
@@ -382,7 +382,7 @@ SymbolVendor::Dump(Stream *s)
{
bool show_context = false;
- s->Printf("%p: ", this);
+ s->Printf("%p: ", static_cast<void*>(this));
s->Indent();
s->PutCString("SymbolVendor");
if (m_sym_file_ap.get())
@@ -427,7 +427,7 @@ SymbolVendor::GetCompileUnitAtIndex(size_t idx)
if (idx < num_compile_units)
{
cu_sp = m_compile_units[idx];
- if (cu_sp.get() == NULL)
+ if (cu_sp.get() == nullptr)
{
m_compile_units[idx] = m_sym_file_ap->ParseCompileUnitAtIndex(idx);
cu_sp = m_compile_units[idx];
@@ -450,7 +450,7 @@ SymbolVendor::GetSymtab ()
return objfile->GetSymtab ();
}
}
- return NULL;
+ return nullptr;
}
void
@@ -468,6 +468,27 @@ SymbolVendor::ClearSymtab()
}
}
+void
+SymbolVendor::SectionFileAddressesChanged ()
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ ObjectFile *module_objfile = module_sp->GetObjectFile ();
+ if (m_sym_file_ap.get())
+ {
+ ObjectFile *symfile_objfile = m_sym_file_ap->GetObjectFile ();
+ if (symfile_objfile != module_objfile)
+ symfile_objfile->SectionFileAddressesChanged ();
+ }
+ Symtab *symtab = GetSymtab ();
+ if (symtab)
+ {
+ symtab->SectionFileAddressesChanged ();
+ }
+ }
+}
+
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
diff --git a/source/Symbol/Symtab.cpp b/source/Symbol/Symtab.cpp
index 430fc1789202..907072c0d906 100644
--- a/source/Symbol/Symtab.cpp
+++ b/source/Symbol/Symtab.cpp
@@ -78,6 +78,13 @@ Symtab::GetNumSymbols() const
}
void
+Symtab::SectionFileAddressesChanged ()
+{
+ m_name_to_index.Clear();
+ m_file_addr_to_index_computed = false;
+}
+
+void
Symtab::Dump (Stream *s, Target *target, SortOrder sort_order)
{
Mutex::Locker locker (m_mutex);
@@ -85,19 +92,19 @@ Symtab::Dump (Stream *s, Target *target, SortOrder sort_order)
// s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
s->Indent();
const FileSpec &file_spec = m_objfile->GetFileSpec();
- const char * object_name = NULL;
+ const char * object_name = nullptr;
if (m_objfile->GetModule())
object_name = m_objfile->GetModule()->GetObjectName().GetCString();
if (file_spec)
- s->Printf("Symtab, file = %s%s%s%s, num_symbols = %zu",
+ s->Printf("Symtab, file = %s%s%s%s, num_symbols = %" PRIu64,
file_spec.GetPath().c_str(),
object_name ? "(" : "",
object_name ? object_name : "",
object_name ? ")" : "",
- m_symbols.size());
+ (uint64_t)m_symbols.size());
else
- s->Printf("Symtab, num_symbols = %zu", m_symbols.size());
+ s->Printf("Symtab, num_symbols = %" PRIu64 "", (uint64_t)m_symbols.size());
if (!m_symbols.empty())
{
@@ -166,7 +173,7 @@ Symtab::Dump(Stream *s, Target *target, std::vector<uint32_t>& indexes) const
const size_t num_symbols = GetNumSymbols();
//s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
s->Indent();
- s->Printf("Symtab %zu symbol indexes (%zu symbols total):\n", indexes.size(), m_symbols.size());
+ s->Printf("Symtab %" PRIu64 " symbol indexes (%" PRIu64 " symbols total):\n", (uint64_t)indexes.size(), (uint64_t)m_symbols.size());
s->IndentMore();
if (!indexes.empty())
@@ -232,7 +239,7 @@ Symtab::SymbolAtIndex(size_t idx)
// when calling this function to avoid performance issues.
if (idx < m_symbols.size())
return &m_symbols[idx];
- return NULL;
+ return nullptr;
}
@@ -243,7 +250,7 @@ Symtab::SymbolAtIndex(size_t idx) const
// when calling this function to avoid performance issues.
if (idx < m_symbols.size())
return &m_symbols[idx];
- return NULL;
+ return nullptr;
}
//----------------------------------------------------------------------
@@ -286,7 +293,7 @@ Symtab::InitNameIndexes()
// The "const char *" in "class_contexts" must come from a ConstString::GetCString()
std::set<const char *> class_contexts;
UniqueCStringMap<uint32_t> mangled_name_to_index;
- std::vector<const char *> symbol_contexts(num_symbols, NULL);
+ std::vector<const char *> symbol_contexts(num_symbols, nullptr);
for (entry.value = 0; entry.value<num_symbols; ++entry.value)
{
@@ -776,7 +783,7 @@ Symtab::FindSymbolWithType (SymbolType symbol_type, Debug symbol_debug_type, Vis
}
}
}
- return NULL;
+ return nullptr;
}
size_t
@@ -854,7 +861,7 @@ Symtab::FindFirstSymbolWithNameAndType (const ConstString &name, SymbolType symb
}
}
}
- return NULL;
+ return nullptr;
}
typedef struct
@@ -867,36 +874,10 @@ typedef struct
} SymbolSearchInfo;
static int
-SymbolWithFileAddress (SymbolSearchInfo *info, const uint32_t *index_ptr)
-{
- const Symbol *curr_symbol = info->symtab->SymbolAtIndex (index_ptr[0]);
- if (curr_symbol == NULL)
- return -1;
-
- const addr_t info_file_addr = info->file_addr;
-
- // lldb::Symbol::GetAddressRangePtr() will only return a non NULL address
- // range if the symbol has a section!
- if (curr_symbol->ValueIsAddress())
- {
- const addr_t curr_file_addr = curr_symbol->GetAddress().GetFileAddress();
- if (info_file_addr < curr_file_addr)
- return -1;
- if (info_file_addr > curr_file_addr)
- return +1;
- info->match_symbol = const_cast<Symbol *>(curr_symbol);
- info->match_index_ptr = index_ptr;
- return 0;
- }
-
- return -1;
-}
-
-static int
SymbolWithClosestFileAddress (SymbolSearchInfo *info, const uint32_t *index_ptr)
{
const Symbol *symbol = info->symtab->SymbolAtIndex (index_ptr[0]);
- if (symbol == NULL)
+ if (symbol == nullptr)
return -1;
const addr_t info_file_addr = info->file_addr;
@@ -921,19 +902,6 @@ SymbolWithClosestFileAddress (SymbolSearchInfo *info, const uint32_t *index_ptr)
return -1;
}
-static SymbolSearchInfo
-FindIndexPtrForSymbolContainingAddress(Symtab* symtab, addr_t file_addr, const uint32_t* indexes, uint32_t num_indexes)
-{
- SymbolSearchInfo info = { symtab, file_addr, NULL, NULL, 0 };
- ::bsearch (&info,
- indexes,
- num_indexes,
- sizeof(uint32_t),
- (ComparisonFunction)SymbolWithClosestFileAddress);
- return info;
-}
-
-
void
Symtab::InitAddressIndexes()
{
@@ -1034,7 +1002,7 @@ Symtab::FindSymbolContainingFileAddress (addr_t file_addr, const uint32_t* index
Mutex::Locker locker (m_mutex);
- SymbolSearchInfo info = { this, file_addr, NULL, NULL, 0 };
+ SymbolSearchInfo info = { this, file_addr, nullptr, nullptr, 0 };
::bsearch (&info,
indexes,
@@ -1064,7 +1032,7 @@ Symtab::FindSymbolContainingFileAddress (addr_t file_addr, const uint32_t* index
if (info.match_offset < symbol_byte_size)
return info.match_symbol;
}
- return NULL;
+ return nullptr;
}
Symbol *
@@ -1078,7 +1046,7 @@ Symtab::FindSymbolContainingFileAddress (addr_t file_addr)
const FileRangeToIndexMap::Entry *entry = m_file_addr_to_index.FindEntryThatContains(file_addr);
if (entry)
return SymbolAtIndex(entry->data);
- return NULL;
+ return nullptr;
}
void
@@ -1157,7 +1125,7 @@ Symtab::FindFunctionSymbols (const ConstString &name,
{
const UniqueCStringMap<uint32_t>::Entry *match;
for (match = m_basename_to_index.FindFirstValueForName(name_cstr);
- match != NULL;
+ match != nullptr;
match = m_basename_to_index.FindNextValueForName(match))
{
symbol_indexes.push_back(match->value);
@@ -1174,7 +1142,7 @@ Symtab::FindFunctionSymbols (const ConstString &name,
{
const UniqueCStringMap<uint32_t>::Entry *match;
for (match = m_method_to_index.FindFirstValueForName(name_cstr);
- match != NULL;
+ match != nullptr;
match = m_method_to_index.FindNextValueForName(match))
{
symbol_indexes.push_back(match->value);
@@ -1191,7 +1159,7 @@ Symtab::FindFunctionSymbols (const ConstString &name,
{
const UniqueCStringMap<uint32_t>::Entry *match;
for (match = m_selector_to_index.FindFirstValueForName(name_cstr);
- match != NULL;
+ match != nullptr;
match = m_selector_to_index.FindNextValueForName(match))
{
symbol_indexes.push_back(match->value);
diff --git a/source/Symbol/Type.cpp b/source/Symbol/Type.cpp
index 073940e8a7f7..4eb538fb1352 100644
--- a/source/Symbol/Type.cpp
+++ b/source/Symbol/Type.cpp
@@ -30,6 +30,8 @@
#include "llvm/ADT/StringRef.h"
+#include "clang/AST/Decl.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -91,7 +93,7 @@ Type::Type
m_name (name),
m_symbol_file (symbol_file),
m_context (context),
- m_encoding_type (NULL),
+ m_encoding_type (nullptr),
m_encoding_uid (encoding_uid),
m_encoding_uid_type (encoding_uid_type),
m_byte_size (byte_size),
@@ -106,9 +108,9 @@ Type::Type () :
std::enable_shared_from_this<Type> (),
UserID (0),
m_name ("<INVALID TYPE>"),
- m_symbol_file (NULL),
- m_context (NULL),
- m_encoding_type (NULL),
+ m_symbol_file (nullptr),
+ m_context (nullptr),
+ m_encoding_type (nullptr),
m_encoding_uid (LLDB_INVALID_UID),
m_encoding_uid_type (eEncodingInvalid),
m_byte_size (0),
@@ -201,16 +203,16 @@ Type::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_name)
void
Type::Dump (Stream *s, bool show_context)
{
- s->Printf("%p: ", this);
+ s->Printf("%p: ", static_cast<void*>(this));
s->Indent();
- *s << "Type" << (const UserID&)*this << ' ';
+ *s << "Type" << static_cast<const UserID&>(*this) << ' ';
if (m_name)
*s << ", name = \"" << m_name << "\"";
if (m_byte_size != 0)
s->Printf(", size = %" PRIu64, m_byte_size);
- if (show_context && m_context != NULL)
+ if (show_context && m_context != nullptr)
{
s->PutCString(", context = ( ");
m_context->DumpSymbolContext(s);
@@ -306,7 +308,7 @@ Type::DumpValue
Type *
Type::GetEncodingType ()
{
- if (m_encoding_type == NULL && m_encoding_uid != LLDB_INVALID_UID)
+ if (m_encoding_type == nullptr && m_encoding_uid != LLDB_INVALID_UID)
m_encoding_type = m_symbol_file->ResolveTypeUID(m_encoding_uid);
return m_encoding_type;
}
@@ -406,7 +408,7 @@ Type::DumpValueInMemory
if (address != LLDB_INVALID_ADDRESS)
{
DataExtractor data;
- Target *target = NULL;
+ Target *target = nullptr;
if (exe_ctx)
target = exe_ctx->GetTargetPtr();
if (target)
@@ -439,14 +441,14 @@ Type::ReadFromMemory (ExecutionContext *exe_ctx, lldb::addr_t addr, AddressType
}
uint8_t* dst = (uint8_t*)data.PeekData(0, byte_size);
- if (dst != NULL)
+ if (dst != nullptr)
{
if (address_type == eAddressTypeHost)
{
// The address is an address in this process, so just copy it
if (addr == 0)
return false;
- memcpy (dst, (uint8_t*)NULL + addr, byte_size);
+ memcpy (dst, (uint8_t*)nullptr + addr, byte_size);
return true;
}
else
@@ -488,7 +490,7 @@ Type::GetDeclaration () const
bool
Type::ResolveClangType (ResolveState clang_type_resolve_state)
{
- Type *encoding_type = NULL;
+ Type *encoding_type = nullptr;
if (!m_clang_type.IsValid())
{
encoding_type = GetEncodingType();
@@ -603,7 +605,7 @@ Type::ResolveClangType (ResolveState clang_type_resolve_state)
// resolved appropriately.
if (m_encoding_uid != LLDB_INVALID_UID)
{
- if (encoding_type == NULL)
+ if (encoding_type == nullptr)
encoding_type = GetEncodingType();
if (encoding_type)
{
@@ -777,7 +779,7 @@ Type::GetTypeScopeAndBasename (const char* &name_cstr,
if (namespace_separator)
{
const char* template_arg_char = ::strchr (basename_cstr, '<');
- while (namespace_separator != NULL)
+ while (namespace_separator != nullptr)
{
if (template_arg_char && namespace_separator > template_arg_char) // but namespace'd template arguments are still good to go
break;
@@ -796,6 +798,13 @@ Type::GetTypeScopeAndBasename (const char* &name_cstr,
}
+ModuleSP
+Type::GetModule()
+{
+ if (m_symbol_file)
+ return m_symbol_file->GetObjectFile()->GetModule();
+ return ModuleSP();
+}
TypeAndOrName::TypeAndOrName () : m_type_pair(), m_type_name()
@@ -927,76 +936,95 @@ TypeAndOrName::HasClangASTType () const
TypeImpl::TypeImpl() :
-m_static_type(),
-m_dynamic_type()
+ m_module_wp(),
+ m_static_type(),
+ m_dynamic_type()
{
}
TypeImpl::TypeImpl(const TypeImpl& rhs) :
-m_static_type(rhs.m_static_type),
-m_dynamic_type(rhs.m_dynamic_type)
+ m_module_wp (rhs.m_module_wp),
+ m_static_type(rhs.m_static_type),
+ m_dynamic_type(rhs.m_dynamic_type)
{
}
-TypeImpl::TypeImpl (lldb::TypeSP type_sp) :
-m_static_type(type_sp),
-m_dynamic_type()
+TypeImpl::TypeImpl (const lldb::TypeSP &type_sp) :
+ m_module_wp (),
+ m_static_type(),
+ m_dynamic_type()
{
+ SetType (type_sp);
}
-TypeImpl::TypeImpl (ClangASTType clang_type) :
-m_static_type(clang_type),
-m_dynamic_type()
+TypeImpl::TypeImpl (const ClangASTType &clang_type) :
+ m_module_wp (),
+ m_static_type(),
+ m_dynamic_type()
{
+ SetType (clang_type);
}
-TypeImpl::TypeImpl (lldb::TypeSP type_sp, ClangASTType dynamic) :
-m_static_type (type_sp),
-m_dynamic_type(dynamic)
+TypeImpl::TypeImpl (const lldb::TypeSP &type_sp, const ClangASTType &dynamic) :
+ m_module_wp (),
+ m_static_type (type_sp),
+ m_dynamic_type(dynamic)
{
+ SetType (type_sp, dynamic);
}
-TypeImpl::TypeImpl (ClangASTType clang_type, ClangASTType dynamic) :
-m_static_type (clang_type),
-m_dynamic_type(dynamic)
+TypeImpl::TypeImpl (const ClangASTType &static_type, const ClangASTType &dynamic_type) :
+ m_module_wp (),
+ m_static_type (),
+ m_dynamic_type()
{
+ SetType (static_type, dynamic_type);
}
-TypeImpl::TypeImpl (TypePair pair, ClangASTType dynamic) :
-m_static_type (pair),
-m_dynamic_type(dynamic)
+TypeImpl::TypeImpl (const TypePair &pair, const ClangASTType &dynamic) :
+ m_module_wp (),
+ m_static_type (),
+ m_dynamic_type()
{
+ SetType (pair, dynamic);
}
void
-TypeImpl::SetType (lldb::TypeSP type_sp)
+TypeImpl::SetType (const lldb::TypeSP &type_sp)
{
m_static_type.SetType(type_sp);
+ if (type_sp)
+ m_module_wp = type_sp->GetModule();
+ else
+ m_module_wp = lldb::ModuleWP();
}
void
-TypeImpl::SetType (ClangASTType clang_type)
+TypeImpl::SetType (const ClangASTType &clang_type)
{
+ m_module_wp = lldb::ModuleWP();
m_static_type.SetType (clang_type);
}
void
-TypeImpl::SetType (lldb::TypeSP type_sp, ClangASTType dynamic)
+TypeImpl::SetType (const lldb::TypeSP &type_sp, const ClangASTType &dynamic)
{
- m_static_type.SetType (type_sp);
+ SetType (type_sp);
m_dynamic_type = dynamic;
}
void
-TypeImpl::SetType (ClangASTType clang_type, ClangASTType dynamic)
+TypeImpl::SetType (const ClangASTType &clang_type, const ClangASTType &dynamic)
{
+ m_module_wp = lldb::ModuleWP();
m_static_type.SetType (clang_type);
m_dynamic_type = dynamic;
}
void
-TypeImpl::SetType (TypePair pair, ClangASTType dynamic)
+TypeImpl::SetType (const TypePair &pair, const ClangASTType &dynamic)
{
+ m_module_wp = pair.GetModule();
m_static_type = pair;
m_dynamic_type = dynamic;
}
@@ -1006,6 +1034,7 @@ TypeImpl::operator = (const TypeImpl& rhs)
{
if (rhs != *this)
{
+ m_module_wp = rhs.m_module_wp;
m_static_type = rhs.m_static_type;
m_dynamic_type = rhs.m_dynamic_type;
}
@@ -1013,24 +1042,55 @@ TypeImpl::operator = (const TypeImpl& rhs)
}
bool
+TypeImpl::CheckModule (lldb::ModuleSP &module_sp) const
+{
+ // Check if we have a module for this type. If we do and the shared pointer is
+ // can be successfully initialized with m_module_wp, return true. Else return false
+ // if we didn't have a module, or if we had a module and it has been deleted. Any
+ // functions doing anything with a TypeSP in this TypeImpl class should call this
+ // function and only do anything with the ivars if this function returns true. If
+ // we have a module, the "module_sp" will be filled in with a strong reference to the
+ // module so that the module will at least stay around long enough for the type
+ // query to succeed.
+ module_sp = m_module_wp.lock();
+ if (!module_sp)
+ {
+ lldb::ModuleWP empty_module_wp;
+ // If either call to "std::weak_ptr::owner_before(...) value returns true, this
+ // indicates that m_module_wp once contained (possibly still does) a reference
+ // to a valid shared pointer. This helps us know if we had a valid reference to
+ // a section which is now invalid because the module it was in was deleted
+ if (empty_module_wp.owner_before(m_module_wp) || m_module_wp.owner_before(empty_module_wp))
+ {
+ // m_module_wp had a valid reference to a module, but all strong references
+ // have been released and the module has been deleted
+ return false;
+ }
+ }
+ // We either successfully locked the module, or didn't have one to begin with
+ return true;
+}
+
+bool
TypeImpl::operator == (const TypeImpl& rhs) const
{
- return m_static_type == rhs.m_static_type &&
- m_dynamic_type == rhs.m_dynamic_type;
+ return m_static_type == rhs.m_static_type && m_dynamic_type == rhs.m_dynamic_type;
}
bool
TypeImpl::operator != (const TypeImpl& rhs) const
{
- return m_static_type != rhs.m_static_type ||
- m_dynamic_type != rhs.m_dynamic_type;
+ return m_static_type != rhs.m_static_type || m_dynamic_type != rhs.m_dynamic_type;
}
bool
TypeImpl::IsValid() const
{
// just a name is not valid
- return m_static_type.IsValid() || m_dynamic_type.IsValid();
+ ModuleSP module_sp;
+ if (CheckModule (module_sp))
+ return m_static_type.IsValid() || m_dynamic_type.IsValid();
+ return false;
}
TypeImpl::operator bool () const
@@ -1041,6 +1101,7 @@ TypeImpl::operator bool () const
void
TypeImpl::Clear()
{
+ m_module_wp = lldb::ModuleWP();
m_static_type.Clear();
m_dynamic_type.Clear();
}
@@ -1048,113 +1109,201 @@ TypeImpl::Clear()
ConstString
TypeImpl::GetName () const
{
- if (m_dynamic_type)
- return m_dynamic_type.GetTypeName();
- return m_static_type.GetName ();
+ ModuleSP module_sp;
+ if (CheckModule (module_sp))
+ {
+ if (m_dynamic_type)
+ return m_dynamic_type.GetTypeName();
+ return m_static_type.GetName ();
+ }
+ return ConstString();
+}
+
+ConstString
+TypeImpl::GetDisplayTypeName () const
+{
+ ModuleSP module_sp;
+ if (CheckModule (module_sp))
+ {
+ if (m_dynamic_type)
+ return m_dynamic_type.GetDisplayTypeName();
+ return m_static_type.GetDisplayTypeName();
+ }
+ return ConstString();
}
TypeImpl
TypeImpl::GetPointerType () const
{
- if (m_dynamic_type.IsValid())
+ ModuleSP module_sp;
+ if (CheckModule (module_sp))
{
- return TypeImpl(m_static_type, m_dynamic_type.GetPointerType());
+ if (m_dynamic_type.IsValid())
+ {
+ return TypeImpl(m_static_type, m_dynamic_type.GetPointerType());
+ }
+ return TypeImpl(m_static_type.GetPointerType());
}
- return TypeImpl(m_static_type.GetPointerType());
+ return TypeImpl();
}
TypeImpl
TypeImpl::GetPointeeType () const
{
- if (m_dynamic_type.IsValid())
+ ModuleSP module_sp;
+ if (CheckModule (module_sp))
{
- return TypeImpl(m_static_type, m_dynamic_type.GetPointeeType());
+ if (m_dynamic_type.IsValid())
+ {
+ return TypeImpl(m_static_type, m_dynamic_type.GetPointeeType());
+ }
+ return TypeImpl(m_static_type.GetPointeeType());
}
- return TypeImpl(m_static_type.GetPointeeType());
+ return TypeImpl();
}
TypeImpl
TypeImpl::GetReferenceType () const
{
- if (m_dynamic_type.IsValid())
+ ModuleSP module_sp;
+ if (CheckModule (module_sp))
{
- return TypeImpl(m_static_type, m_dynamic_type.GetLValueReferenceType());
+ if (m_dynamic_type.IsValid())
+ {
+ return TypeImpl(m_static_type, m_dynamic_type.GetLValueReferenceType());
+ }
+ return TypeImpl(m_static_type.GetReferenceType());
}
- return TypeImpl(m_static_type.GetReferenceType());
+ return TypeImpl();
}
TypeImpl
TypeImpl::GetTypedefedType () const
{
- if (m_dynamic_type.IsValid())
+ ModuleSP module_sp;
+ if (CheckModule (module_sp))
{
- return TypeImpl(m_static_type, m_dynamic_type.GetTypedefedType());
+ if (m_dynamic_type.IsValid())
+ {
+ return TypeImpl(m_static_type, m_dynamic_type.GetTypedefedType());
+ }
+ return TypeImpl(m_static_type.GetTypedefedType());
}
- return TypeImpl(m_static_type.GetTypedefedType());
+ return TypeImpl();
}
TypeImpl
TypeImpl::GetDereferencedType () const
{
- if (m_dynamic_type.IsValid())
+ ModuleSP module_sp;
+ if (CheckModule (module_sp))
{
- return TypeImpl(m_static_type, m_dynamic_type.GetNonReferenceType());
+ if (m_dynamic_type.IsValid())
+ {
+ return TypeImpl(m_static_type, m_dynamic_type.GetNonReferenceType());
+ }
+ return TypeImpl(m_static_type.GetDereferencedType());
}
- return TypeImpl(m_static_type.GetDereferencedType());
+ return TypeImpl();
}
TypeImpl
TypeImpl::GetUnqualifiedType() const
{
- if (m_dynamic_type.IsValid())
+ ModuleSP module_sp;
+ if (CheckModule (module_sp))
{
- return TypeImpl(m_static_type, m_dynamic_type.GetFullyUnqualifiedType());
+ if (m_dynamic_type.IsValid())
+ {
+ return TypeImpl(m_static_type, m_dynamic_type.GetFullyUnqualifiedType());
+ }
+ return TypeImpl(m_static_type.GetUnqualifiedType());
}
- return TypeImpl(m_static_type.GetUnqualifiedType());
+ return TypeImpl();
}
TypeImpl
TypeImpl::GetCanonicalType() const
{
- if (m_dynamic_type.IsValid())
+ ModuleSP module_sp;
+ if (CheckModule (module_sp))
{
- return TypeImpl(m_static_type, m_dynamic_type.GetCanonicalType());
+ if (m_dynamic_type.IsValid())
+ {
+ return TypeImpl(m_static_type, m_dynamic_type.GetCanonicalType());
+ }
+ return TypeImpl(m_static_type.GetCanonicalType());
}
- return TypeImpl(m_static_type.GetCanonicalType());
+ return TypeImpl();
}
ClangASTType
TypeImpl::GetClangASTType (bool prefer_dynamic)
{
- if (prefer_dynamic)
+ ModuleSP module_sp;
+ if (CheckModule (module_sp))
{
- if (m_dynamic_type.IsValid())
- return m_dynamic_type;
+ if (prefer_dynamic)
+ {
+ if (m_dynamic_type.IsValid())
+ return m_dynamic_type;
+ }
+ return m_static_type.GetClangASTType();
}
- return m_static_type.GetClangASTType();
+ return ClangASTType();
}
clang::ASTContext *
TypeImpl::GetClangASTContext (bool prefer_dynamic)
{
- if (prefer_dynamic)
+ ModuleSP module_sp;
+ if (CheckModule (module_sp))
{
- if (m_dynamic_type.IsValid())
- return m_dynamic_type.GetASTContext();
+ if (prefer_dynamic)
+ {
+ if (m_dynamic_type.IsValid())
+ return m_dynamic_type.GetASTContext();
+ }
+ return m_static_type.GetClangASTContext();
}
- return m_static_type.GetClangASTContext();
+ return NULL;
}
bool
TypeImpl::GetDescription (lldb_private::Stream &strm,
- lldb::DescriptionLevel description_level)
+ lldb::DescriptionLevel description_level)
{
- if (m_dynamic_type.IsValid())
+ ModuleSP module_sp;
+ if (CheckModule (module_sp))
{
- strm.Printf("Dynamic:\n");
- m_dynamic_type.DumpTypeDescription(&strm);
- strm.Printf("\nStatic:\n");
+ if (m_dynamic_type.IsValid())
+ {
+ strm.Printf("Dynamic:\n");
+ m_dynamic_type.DumpTypeDescription(&strm);
+ strm.Printf("\nStatic:\n");
+ }
+ m_static_type.GetClangASTType().DumpTypeDescription(&strm);
+ }
+ else
+ {
+ strm.PutCString("Invalid TypeImpl module for type has been deleted\n");
}
- m_static_type.GetClangASTType().DumpTypeDescription(&strm);
return true;
}
+
+TypeEnumMemberImpl::TypeEnumMemberImpl (const clang::EnumConstantDecl* enum_member_decl,
+ const lldb_private::ClangASTType& integer_type) :
+ m_integer_type_sp(),
+ m_name(),
+ m_value(),
+ m_valid(false)
+
+{
+ if (enum_member_decl)
+ {
+ m_integer_type_sp.reset(new TypeImpl(integer_type));
+ m_name = ConstString(enum_member_decl->getNameAsString().c_str());
+ m_value = enum_member_decl->getInitVal();
+ m_valid = true;
+ }
+}
diff --git a/source/Symbol/TypeList.cpp b/source/Symbol/TypeList.cpp
index a033edd22e1f..8d97b2ba25cc 100644
--- a/source/Symbol/TypeList.cpp
+++ b/source/Symbol/TypeList.cpp
@@ -179,49 +179,6 @@ TypeList::Dump(Stream *s, bool show_context)
}
}
-// depending on implementation details, type lookup might fail because of
-// embedded spurious namespace:: prefixes. this call strips them, paying
-// attention to the fact that a type might have namespace'd type names as
-// arguments to templates, and those must not be stripped off
-static bool
-GetTypeScopeAndBasename(const char* name_cstr, std::string &scope, std::string &basename, bool *exact_ptr)
-{
- // Protect against null c string.
-
- if (name_cstr && name_cstr[0])
- {
- const char *basename_cstr = name_cstr;
- const char* namespace_separator = ::strstr (basename_cstr, "::");
- if (namespace_separator)
- {
- const char* template_arg_char = ::strchr (basename_cstr, '<');
- while (namespace_separator != NULL)
- {
- if (template_arg_char && namespace_separator > template_arg_char) // but namespace'd template arguments are still good to go
- break;
- basename_cstr = namespace_separator + 2;
- namespace_separator = strstr(basename_cstr, "::");
- }
- if (basename_cstr > name_cstr)
- {
- scope.assign (name_cstr, basename_cstr - name_cstr);
- if (scope.size() >= 2 && scope[0] == ':' && scope[1] == ':')
- {
- // The typename passed in started with "::" so make sure we only do exact matches
- if (exact_ptr)
- *exact_ptr = true;
- // Strip the leading "::" as this won't ever show in qualified typenames we get
- // from clang.
- scope.erase(0,2);
- }
- basename.assign (basename_cstr);
- return true;
- }
- }
- }
- return false;
-}
-
void
TypeList::RemoveMismatchedTypes (const char *qualified_typename,
bool exact_match)
diff --git a/source/Symbol/UnwindPlan.cpp b/source/Symbol/UnwindPlan.cpp
index 7b361e7d2eb9..ff0468e314d8 100644
--- a/source/Symbol/UnwindPlan.cpp
+++ b/source/Symbol/UnwindPlan.cpp
@@ -126,7 +126,7 @@ UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_pla
case inOtherRegister:
{
- const RegisterInfo *other_reg_info = NULL;
+ const RegisterInfo *other_reg_info = nullptr;
if (unwind_plan)
other_reg_info = unwind_plan->GetRegisterInfo (thread, m_location.reg_num);
if (other_reg_info)
@@ -313,6 +313,19 @@ UnwindPlan::AppendRow (const UnwindPlan::RowSP &row_sp)
m_row_list.back() = row_sp;
}
+void
+UnwindPlan::InsertRow (const UnwindPlan::RowSP &row_sp)
+{
+ collection::iterator it = m_row_list.begin();
+ while (it != m_row_list.end()) {
+ RowSP row = *it;
+ if (row->GetOffset() > row_sp->GetOffset())
+ break;
+ it++;
+ }
+ m_row_list.insert(it, row_sp);
+}
+
UnwindPlan::RowSP
UnwindPlan::GetRowForFunctionOffset (int offset) const
{
@@ -326,7 +339,7 @@ UnwindPlan::GetRowForFunctionOffset (int offset) const
collection::const_iterator pos, end = m_row_list.end();
for (pos = m_row_list.begin(); pos != end; ++pos)
{
- if ((*pos)->GetOffset() <= offset)
+ if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset))
row = *pos;
else
break;
@@ -381,7 +394,7 @@ UnwindPlan::PlanValidAtAddress (Address addr)
if (log)
{
StreamString s;
- if (addr.Dump (&s, NULL, Address::DumpStyleSectionNameOffset))
+ if (addr.Dump (&s, nullptr, Address::DumpStyleSectionNameOffset))
{
log->Printf ("UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s' at address %s",
m_source_name.GetCString(), s.GetData());
@@ -397,13 +410,13 @@ UnwindPlan::PlanValidAtAddress (Address addr)
// If the 0th Row of unwind instructions is missing, or if it doesn't provide
// a register to use to find the Canonical Frame Address, this is not a valid UnwindPlan.
- if (GetRowAtIndex(0).get() == NULL || GetRowAtIndex(0)->GetCFARegister() == LLDB_INVALID_REGNUM)
+ if (GetRowAtIndex(0).get() == nullptr || GetRowAtIndex(0)->GetCFARegister() == LLDB_INVALID_REGNUM)
{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
if (log)
{
StreamString s;
- if (addr.Dump (&s, NULL, Address::DumpStyleSectionNameOffset))
+ if (addr.Dump (&s, nullptr, Address::DumpStyleSectionNameOffset))
{
log->Printf ("UnwindPlan is invalid -- no CFA register defined in row 0 for UnwindPlan '%s' at address %s",
m_source_name.GetCString(), s.GetData());
@@ -480,6 +493,6 @@ UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const
return reg_ctx->GetRegisterInfoAtIndex (reg);
}
}
- return NULL;
+ return nullptr;
}
diff --git a/source/Symbol/UnwindTable.cpp b/source/Symbol/UnwindTable.cpp
index 33eb4d6c092b..df9f5b932565 100644
--- a/source/Symbol/UnwindTable.cpp
+++ b/source/Symbol/UnwindTable.cpp
@@ -17,7 +17,6 @@
#include "lldb/Symbol/FuncUnwinders.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/DWARFCallFrameInfo.h"
-#include "lldb/Target/UnwindAssembly.h"
// There is one UnwindTable object per ObjectFile.
// It contains a list of Unwind objects -- one per function, populated lazily -- for the ObjectFile.
@@ -30,8 +29,8 @@ UnwindTable::UnwindTable (ObjectFile& objfile) :
m_object_file (objfile),
m_unwinds (),
m_initialized (false),
- m_assembly_profiler (NULL),
- m_eh_frame (NULL)
+ m_mutex (),
+ m_eh_frame (nullptr)
{
}
@@ -44,6 +43,11 @@ UnwindTable::Initialize ()
if (m_initialized)
return;
+ Mutex::Locker locker(m_mutex);
+
+ if (m_initialized) // check again once we've acquired the lock
+ return;
+
SectionList* sl = m_object_file.GetSectionList ();
if (sl)
{
@@ -54,12 +58,7 @@ UnwindTable::Initialize ()
}
}
- ArchSpec arch;
- if (m_object_file.GetArchitecture (arch))
- {
- m_assembly_profiler = UnwindAssembly::FindPlugin (arch);
- m_initialized = true;
- }
+ m_initialized = true;
}
UnwindTable::~UnwindTable ()
@@ -75,6 +74,8 @@ UnwindTable::GetFuncUnwindersContainingAddress (const Address& addr, SymbolConte
Initialize();
+ Mutex::Locker locker(m_mutex);
+
// There is an UnwindTable per object file, so we can safely use file handles
addr_t file_addr = addr.GetFileAddress();
iterator end = m_unwinds.end ();
@@ -94,13 +95,13 @@ UnwindTable::GetFuncUnwindersContainingAddress (const Address& addr, SymbolConte
if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, false, range) || !range.GetBaseAddress().IsValid())
{
// Does the eh_frame unwind info has a function bounds for this addr?
- if (m_eh_frame == NULL || !m_eh_frame->GetAddressRange (addr, range))
+ if (m_eh_frame == nullptr || !m_eh_frame->GetAddressRange (addr, range))
{
return no_unwind_found;
}
}
- FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, m_assembly_profiler, range));
+ FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, range));
m_unwinds.insert (insert_pos, std::make_pair(range.GetBaseAddress().GetFileAddress(), func_unwinder_sp));
// StreamFile s(stdout, false);
// Dump (s);
@@ -121,13 +122,13 @@ UnwindTable::GetUncachedFuncUnwindersContainingAddress (const Address& addr, Sym
if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, false, range) || !range.GetBaseAddress().IsValid())
{
// Does the eh_frame unwind info has a function bounds for this addr?
- if (m_eh_frame == NULL || !m_eh_frame->GetAddressRange (addr, range))
+ if (m_eh_frame == nullptr || !m_eh_frame->GetAddressRange (addr, range))
{
return no_unwind_found;
}
}
- FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, m_assembly_profiler, range));
+ FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, range));
return func_unwinder_sp;
}
@@ -135,6 +136,7 @@ UnwindTable::GetUncachedFuncUnwindersContainingAddress (const Address& addr, Sym
void
UnwindTable::Dump (Stream &s)
{
+ Mutex::Locker locker(m_mutex);
s.Printf("UnwindTable for '%s':\n", m_object_file.GetFileSpec().GetPath().c_str());
const_iterator begin = m_unwinds.begin();
const_iterator end = m_unwinds.end();
@@ -151,3 +153,9 @@ UnwindTable::GetEHFrameInfo ()
Initialize();
return m_eh_frame;
}
+
+bool
+UnwindTable::GetArchitecture (lldb_private::ArchSpec &arch)
+{
+ return m_object_file.GetArchitecture (arch);
+}
diff --git a/source/Symbol/Variable.cpp b/source/Symbol/Variable.cpp
index 36fe3b1d79d4..e6a9b027fc13 100644
--- a/source/Symbol/Variable.cpp
+++ b/source/Symbol/Variable.cpp
@@ -87,13 +87,13 @@ Variable::GetType()
{
if (m_symfile_type_sp)
return m_symfile_type_sp->GetType();
- return NULL;
+ return nullptr;
}
void
Variable::Dump(Stream *s, bool show_context) const
{
- s->Printf("%p: ", this);
+ s->Printf("%p: ", static_cast<const void*>(this));
s->Indent();
*s << "Variable" << (const UserID&)*this;
@@ -123,7 +123,7 @@ Variable::Dump(Stream *s, bool show_context) const
}
}
- if (show_context && m_owner_scope != NULL)
+ if (show_context && m_owner_scope != nullptr)
{
s->PutCString(", context = ( ");
m_owner_scope->DumpSymbolContext(s);
@@ -144,7 +144,7 @@ Variable::Dump(Stream *s, bool show_context) const
if (variable_sc.function)
loclist_base_addr = variable_sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
}
- ABI *abi = NULL;
+ ABI *abi = nullptr;
if (m_owner_scope)
{
ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule());
@@ -171,12 +171,12 @@ Variable::DumpDeclaration (Stream *s, bool show_fullpaths, bool show_module)
{
SymbolContext sc;
m_owner_scope->CalculateSymbolContext(&sc);
- sc.block = NULL;
+ sc.block = nullptr;
sc.line_entry.Clear();
bool show_inlined_frames = false;
dumped_declaration_info = sc.DumpStopContext (s,
- NULL,
+ nullptr,
Address(),
show_fullpaths,
show_module,
@@ -277,7 +277,7 @@ Variable::IsInScope (StackFrame *frame)
{
case eValueTypeRegister:
case eValueTypeRegisterSet:
- return frame != NULL;
+ return frame != nullptr;
case eValueTypeConstResult:
case eValueTypeVariableGlobal:
@@ -297,7 +297,7 @@ Variable::IsInScope (StackFrame *frame)
CalculateSymbolContext (&variable_sc);
// Check for static or global variable defined at the compile unit
// level that wasn't defined in a block
- if (variable_sc.block == NULL)
+ if (variable_sc.block == nullptr)
return true;
if (variable_sc.block == deepest_frame_block)
@@ -419,7 +419,7 @@ Variable::GetValuesForVariableExpressionPath (const char *variable_expr_path,
const char *variable_sub_expr_path = variable_expr_path + variable_name.size();
if (*variable_sub_expr_path)
{
- const char* first_unparsed = NULL;
+ const char* first_unparsed = nullptr;
ValueObject::ExpressionPathScanEndReason reason_to_stop;
ValueObject::ExpressionPathEndResultType final_value_type;
ValueObject::GetValueForExpressionPathOptions options;
@@ -485,7 +485,7 @@ Variable::DumpLocationForAddress (Stream *s, const Address &address)
CalculateSymbolContext(&sc);
if (sc.module_sp == address.GetModule())
{
- ABI *abi = NULL;
+ ABI *abi = nullptr;
if (m_owner_scope)
{
ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule());
@@ -553,7 +553,7 @@ PrivateAutoCompleteMembers (StackFrame *frame,
{
for (uint32_t i = 0; i < num_bases; ++i)
{
- ClangASTType base_class_type (clang_type.GetDirectBaseClassAtIndex (i, NULL));
+ ClangASTType base_class_type (clang_type.GetDirectBaseClassAtIndex (i, nullptr));
PrivateAutoCompleteMembers (frame,
partial_member_name,
@@ -571,7 +571,7 @@ PrivateAutoCompleteMembers (StackFrame *frame,
{
for (uint32_t i = 0; i < num_vbases; ++i)
{
- ClangASTType vbase_class_type (clang_type.GetVirtualBaseClassAtIndex(i,NULL));
+ ClangASTType vbase_class_type (clang_type.GetVirtualBaseClassAtIndex(i,nullptr));
PrivateAutoCompleteMembers (frame,
partial_member_name,
@@ -592,7 +592,7 @@ PrivateAutoCompleteMembers (StackFrame *frame,
{
std::string member_name;
- ClangASTType member_clang_type = clang_type.GetFieldAtIndex (i, member_name, NULL, NULL, NULL);
+ ClangASTType member_clang_type = clang_type.GetFieldAtIndex (i, member_name, nullptr, nullptr, nullptr);
if (partial_member_name.empty() ||
member_name.find(partial_member_name) == 0)
diff --git a/source/Target/ABI.cpp b/source/Target/ABI.cpp
index 06215221d961..e02f360680fb 100644
--- a/source/Target/ABI.cpp
+++ b/source/Target/ABI.cpp
@@ -51,7 +51,6 @@ ABI::~ABI()
{
}
-
bool
ABI::GetRegisterInfoByName (const ConstString &name, RegisterInfo &info)
{
@@ -172,4 +171,37 @@ ABI::GetReturnValueObject (Thread &thread,
return return_valobj_sp;
}
+ValueObjectSP
+ABI::GetReturnValueObject(Thread &thread, llvm::Type &ast_type, bool persistent) const
+{
+ ValueObjectSP return_valobj_sp;
+ return_valobj_sp = GetReturnValueObjectImpl( thread, ast_type );
+ return return_valobj_sp;
+}
+
+// specialized to work with llvm IR types
+//
+// for now we will specify a default implementation so that we don't need to
+// modify other ABIs
+lldb::ValueObjectSP
+ABI::GetReturnValueObjectImpl( Thread &thread, llvm::Type &ir_type ) const
+{
+ ValueObjectSP return_valobj_sp;
+
+ /* this is a dummy and will only be called if an ABI does not override this */
+
+ return return_valobj_sp;
+}
+bool
+ABI::PrepareTrivialCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ llvm::Type &returntype,
+ llvm::ArrayRef<ABI::CallArgument> args) const
+{
+ // dummy prepare trivial call
+ assert( !"Should never get here!" );
+ return false;
+}
diff --git a/source/Target/FileAction.cpp b/source/Target/FileAction.cpp
new file mode 100644
index 000000000000..18b039998bc7
--- /dev/null
+++ b/source/Target/FileAction.cpp
@@ -0,0 +1,95 @@
+//===-- FileAction.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <fcntl.h>
+
+#if defined(_WIN32)
+#include "lldb/Host/Windows/win32.h" // For O_NOCTTY
+#endif
+
+#include "lldb/Target/FileAction.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------------
+// FileAction member functions
+//----------------------------------------------------------------------------
+
+FileAction::FileAction()
+ : m_action(eFileActionNone)
+ , m_fd(-1)
+ , m_arg(-1)
+ , m_path()
+{
+}
+
+void
+FileAction::Clear()
+{
+ m_action = eFileActionNone;
+ m_fd = -1;
+ m_arg = -1;
+ m_path.clear();
+}
+
+const char *
+FileAction::GetPath() const
+{
+ if (m_path.empty())
+ return NULL;
+ return m_path.c_str();
+}
+
+bool
+FileAction::Open(int fd, const char *path, bool read, bool write)
+{
+ if ((read || write) && fd >= 0 && path && path[0])
+ {
+ m_action = eFileActionOpen;
+ m_fd = fd;
+ if (read && write)
+ m_arg = O_NOCTTY | O_CREAT | O_RDWR;
+ else if (read)
+ m_arg = O_NOCTTY | O_RDONLY;
+ else
+ m_arg = O_NOCTTY | O_CREAT | O_WRONLY;
+ m_path.assign(path);
+ return true;
+ }
+ else
+ {
+ Clear();
+ }
+ return false;
+}
+
+bool
+FileAction::Close(int fd)
+{
+ Clear();
+ if (fd >= 0)
+ {
+ m_action = eFileActionClose;
+ m_fd = fd;
+ }
+ return m_fd >= 0;
+}
+
+bool
+FileAction::Duplicate(int fd, int dup_fd)
+{
+ Clear();
+ if (fd >= 0 && dup_fd >= 0)
+ {
+ m_action = eFileActionDuplicate;
+ m_fd = fd;
+ m_arg = dup_fd;
+ }
+ return m_fd >= 0;
+}
diff --git a/source/Target/JITLoader.cpp b/source/Target/JITLoader.cpp
new file mode 100644
index 000000000000..8536d690ece0
--- /dev/null
+++ b/source/Target/JITLoader.cpp
@@ -0,0 +1,38 @@
+//===-- JITLoader.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/JITLoader.h"
+#include "lldb/Target/JITLoaderList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Core/PluginManager.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+JITLoader::LoadPlugins (Process *process, JITLoaderList &list)
+{
+ JITLoaderCreateInstance create_callback = NULL;
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetJITLoaderCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ JITLoaderSP instance_sp(create_callback(process, false));
+ if (instance_sp)
+ list.Append(std::move(instance_sp));
+ }
+}
+
+JITLoader::JITLoader(Process *process) :
+ m_process (process)
+{
+}
+
+JITLoader::~JITLoader()
+{
+}
diff --git a/source/Target/JITLoaderList.cpp b/source/Target/JITLoaderList.cpp
new file mode 100644
index 000000000000..24a73b7fd516
--- /dev/null
+++ b/source/Target/JITLoaderList.cpp
@@ -0,0 +1,77 @@
+//===-- JITLoader.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/JITLoader.h"
+#include "lldb/Target/JITLoaderList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+JITLoaderList::JITLoaderList()
+ : m_jit_loaders_vec(), m_jit_loaders_mutex(Mutex::eMutexTypeRecursive)
+{
+}
+
+JITLoaderList::~JITLoaderList()
+{
+}
+
+void
+JITLoaderList::Append (const JITLoaderSP &jit_loader_sp)
+{
+ Mutex::Locker locker(m_jit_loaders_mutex);
+ m_jit_loaders_vec.push_back(jit_loader_sp);
+}
+
+void
+JITLoaderList::Remove (const JITLoaderSP &jit_loader_sp)
+{
+ Mutex::Locker locker(m_jit_loaders_mutex);
+ m_jit_loaders_vec.erase(std::remove(m_jit_loaders_vec.begin(),
+ m_jit_loaders_vec.end(), jit_loader_sp),
+ m_jit_loaders_vec.end());
+}
+
+size_t
+JITLoaderList::GetSize() const
+{
+ return m_jit_loaders_vec.size();
+}
+
+JITLoaderSP
+JITLoaderList::GetLoaderAtIndex (size_t idx)
+{
+ Mutex::Locker locker(m_jit_loaders_mutex);
+ return m_jit_loaders_vec[idx];
+}
+
+void
+JITLoaderList::DidLaunch()
+{
+ Mutex::Locker locker(m_jit_loaders_mutex);
+ for (auto const &jit_loader : m_jit_loaders_vec)
+ jit_loader->DidLaunch();
+}
+
+void
+JITLoaderList::DidAttach()
+{
+ Mutex::Locker locker(m_jit_loaders_mutex);
+ for (auto const &jit_loader : m_jit_loaders_vec)
+ jit_loader->DidAttach();
+}
+
+void
+JITLoaderList::ModulesDidLoad(ModuleList &module_list)
+{
+ Mutex::Locker locker(m_jit_loaders_mutex);
+ for (auto const &jit_loader : m_jit_loaders_vec)
+ jit_loader->ModulesDidLoad(module_list);
+}
diff --git a/source/Target/LanguageRuntime.cpp b/source/Target/LanguageRuntime.cpp
index a2b7f1d6ae85..9d48d8b2de7f 100644
--- a/source/Target/LanguageRuntime.cpp
+++ b/source/Target/LanguageRuntime.cpp
@@ -307,6 +307,18 @@ struct language_name_pair language_names[] =
{ "upc", eLanguageTypeUPC },
{ "d", eLanguageTypeD },
{ "python", eLanguageTypePython },
+ { "opencl", eLanguageTypeOpenCL },
+ { "go", eLanguageTypeGo },
+ { "modula3", eLanguageTypeModula3 },
+ { "haskell", eLanguageTypeHaskell },
+ { "c++03", eLanguageTypeC_plus_plus_03 },
+ { "c++11", eLanguageTypeC_plus_plus_11 },
+ { "ocaml", eLanguageTypeOCaml },
+ { "rust", eLanguageTypeRust },
+ { "c11", eLanguageTypeC11 },
+ { "swift", eLanguageTypeSwift },
+ { "julia", eLanguageTypeJulia },
+ { "dylan", eLanguageTypeDylan },
// Now synonyms, in arbitrary order
{ "objc", eLanguageTypeObjC },
{ "objc++", eLanguageTypeObjC_plus_plus }
diff --git a/source/Target/Memory.cpp b/source/Target/Memory.cpp
index 3c8d483f3003..b212fcd23a45 100644
--- a/source/Target/Memory.cpp
+++ b/source/Target/Memory.cpp
@@ -9,6 +9,7 @@
#include "lldb/Target/Memory.h"
// C Includes
+#include <inttypes.h>
// C++ Includes
// Other libraries and framework includes
// Project includes
@@ -119,6 +120,19 @@ MemoryCache::Read (addr_t addr,
Error &error)
{
size_t bytes_left = dst_len;
+
+ // If this memory read request is larger than the cache line size, then
+ // we (1) try to read as much of it at once as possible, and (2) don't
+ // add the data to the memory cache. We don't want to split a big read
+ // up into more separate reads than necessary, and with a large memory read
+ // request, it is unlikely that the caller function will ask for the next
+ // 4 bytes after the large memory read - so there's little benefit to saving
+ // it in the cache.
+ if (dst && dst_len > m_cache_line_byte_size)
+ {
+ return m_process.ReadMemoryFromInferior (addr, dst, dst_len, error);
+ }
+
if (dst && bytes_left > 0)
{
const uint32_t cache_line_byte_size = m_cache_line_byte_size;
@@ -227,16 +241,16 @@ lldb::addr_t
AllocatedBlock::ReserveBlock (uint32_t size)
{
addr_t addr = LLDB_INVALID_ADDRESS;
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
if (size <= m_byte_size)
{
const uint32_t needed_chunks = CalculateChunksNeededForSize (size);
- Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
if (m_offset_to_chunk_size.empty())
{
m_offset_to_chunk_size[0] = needed_chunks;
if (log)
- log->Printf ("[1] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, 0, needed_chunks, m_chunk_size);
+ log->Printf ("[1] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", this, size, size, 0, needed_chunks, m_chunk_size);
addr = m_addr;
}
else
@@ -254,7 +268,7 @@ AllocatedBlock::ReserveBlock (uint32_t size)
{
m_offset_to_chunk_size[last_offset] = needed_chunks;
if (log)
- log->Printf ("[2] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, last_offset, needed_chunks, m_chunk_size);
+ log->Printf ("[2] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - num_chunks %lu", this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());
addr = m_addr + last_offset;
break;
}
@@ -270,7 +284,7 @@ AllocatedBlock::ReserveBlock (uint32_t size)
{
m_offset_to_chunk_size[last_offset] = needed_chunks;
if (log)
- log->Printf ("[3] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, last_offset, needed_chunks, m_chunk_size);
+ log->Printf ("[3] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - num_chunks %lu", this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());
addr = m_addr + last_offset;
break;
}
@@ -329,9 +343,9 @@ AllocatedBlock::ReserveBlock (uint32_t size)
// return m_addr + m_chunk_size * first_chunk_idx;
// }
}
- Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
+
if (log)
- log->Printf ("AllocatedBlock::ReserveBlock (size = %u (0x%x)) => 0x%16.16" PRIx64, size, size, (uint64_t)addr);
+ log->Printf ("AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => 0x%16.16" PRIx64, this, size, size, (uint64_t)addr);
return addr;
}
@@ -348,7 +362,7 @@ AllocatedBlock::FreeBlock (addr_t addr)
}
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
if (log)
- log->Printf ("AllocatedBlock::FreeBlock (addr = 0x%16.16" PRIx64 ") => %i", (uint64_t)addr, success);
+ log->Printf ("AllocatedBlock::FreeBlock(%p) (addr = 0x%16.16" PRIx64 ") => %i, num_chunks: %lu", this, (uint64_t)addr, success, m_offset_to_chunk_size.size());
return success;
}
@@ -395,8 +409,8 @@ AllocatedMemoryCache::AllocatePage (uint32_t byte_size,
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
{
- log->Printf ("Process::DoAllocateMemory (byte_size = 0x%8.8zx, permissions = %s) => 0x%16.16" PRIx64,
- page_byte_size,
+ log->Printf ("Process::DoAllocateMemory (byte_size = 0x%8.8" PRIx32 ", permissions = %s) => 0x%16.16" PRIx64,
+ (uint32_t)page_byte_size,
GetPermissionsAsCString(permissions),
(uint64_t)addr);
}
@@ -422,6 +436,8 @@ AllocatedMemoryCache::AllocateMemory (size_t byte_size,
for (PermissionsToBlockMap::iterator pos = range.first; pos != range.second; ++pos)
{
addr = (*pos).second->ReserveBlock (byte_size);
+ if (addr != LLDB_INVALID_ADDRESS)
+ break;
}
if (addr == LLDB_INVALID_ADDRESS)
@@ -433,7 +449,7 @@ AllocatedMemoryCache::AllocateMemory (size_t byte_size,
}
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("AllocatedMemoryCache::AllocateMemory (byte_size = 0x%8.8zx, permissions = %s) => 0x%16.16" PRIx64, byte_size, GetPermissionsAsCString(permissions), (uint64_t)addr);
+ log->Printf ("AllocatedMemoryCache::AllocateMemory (byte_size = 0x%8.8" PRIx32 ", permissions = %s) => 0x%16.16" PRIx64, (uint32_t)byte_size, GetPermissionsAsCString(permissions), (uint64_t)addr);
return addr;
}
diff --git a/source/Target/NativeRegisterContext.cpp b/source/Target/NativeRegisterContext.cpp
new file mode 100644
index 000000000000..d84e2279a459
--- /dev/null
+++ b/source/Target/NativeRegisterContext.cpp
@@ -0,0 +1,470 @@
+//===-- NativeRegisterContext.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/Target/NativeRegisterContext.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+
+#include "lldb/lldb-private-log.h"
+
+#include "Host/common/NativeProcessProtocol.h"
+#include "Host/common/NativeThreadProtocol.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+NativeRegisterContext::NativeRegisterContext (NativeThreadProtocol &thread, uint32_t concrete_frame_idx) :
+ m_thread (thread),
+ m_concrete_frame_idx (concrete_frame_idx)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+NativeRegisterContext::~NativeRegisterContext()
+{
+}
+
+// FIXME revisit invalidation, process stop ids, etc. Right now we don't
+// support caching in NativeRegisterContext. We can do this later by
+// utilizing NativeProcessProtocol::GetStopID () and adding a stop id to
+// NativeRegisterContext.
+
+// void
+// NativeRegisterContext::InvalidateIfNeeded (bool force)
+// {
+// ProcessSP process_sp (m_thread.GetProcess());
+// bool invalidate = force;
+// uint32_t process_stop_id = UINT32_MAX;
+
+// if (process_sp)
+// process_stop_id = process_sp->GetStopID();
+// else
+// invalidate = true;
+
+// if (!invalidate)
+// invalidate = process_stop_id != GetStopID();
+
+// if (invalidate)
+// {
+// InvalidateAllRegisters ();
+// SetStopID (process_stop_id);
+// }
+// }
+
+
+const RegisterInfo *
+NativeRegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx)
+{
+ if (reg_name && reg_name[0])
+ {
+ const uint32_t num_registers = GetRegisterCount();
+ for (uint32_t reg = start_idx; reg < num_registers; ++reg)
+ {
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
+
+ if ((reg_info->name != nullptr && ::strcasecmp (reg_info->name, reg_name) == 0) ||
+ (reg_info->alt_name != nullptr && ::strcasecmp (reg_info->alt_name, reg_name) == 0))
+ {
+ return reg_info;
+ }
+ }
+ }
+ return nullptr;
+}
+
+const RegisterInfo *
+NativeRegisterContext::GetRegisterInfo (uint32_t kind, uint32_t num)
+{
+ const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num);
+ if (reg_num == LLDB_INVALID_REGNUM)
+ return nullptr;
+ return GetRegisterInfoAtIndex (reg_num);
+}
+
+const char *
+NativeRegisterContext::GetRegisterName (uint32_t reg)
+{
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info)
+ return reg_info->name;
+ return nullptr;
+}
+
+const char*
+NativeRegisterContext::GetRegisterSetNameForRegisterAtIndex (uint32_t reg_index) const
+{
+ const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ return nullptr;
+
+ for (uint32_t set_index = 0; set_index < GetRegisterSetCount (); ++set_index)
+ {
+ const RegisterSet *const reg_set = GetRegisterSet (set_index);
+ if (!reg_set)
+ continue;
+
+ for (uint32_t reg_num_index = 0; reg_num_index < reg_set->num_registers; ++reg_num_index)
+ {
+ const uint32_t reg_num = reg_set->registers[reg_num_index];
+ // FIXME double check we're checking the right register kind here.
+ if (reg_info->kinds[RegisterKind::eRegisterKindLLDB] == reg_num)
+ {
+ // The given register is a member of this register set. Return the register set name.
+ return reg_set->name;
+ }
+ }
+ }
+
+ // Didn't find it.
+ return nullptr;
+}
+
+lldb::addr_t
+NativeRegisterContext::GetPC (lldb::addr_t fail_value)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ if (log)
+ log->Printf ("NativeRegisterContext::%s using reg index %" PRIu32 " (default %" PRIu64 ")", __FUNCTION__, reg, fail_value);
+
+ const uint64_t retval = ReadRegisterAsUnsigned (reg, fail_value);
+
+ if (log)
+ log->Printf ("NativeRegisterContext::%s " PRIu32 " retval %" PRIu64, __FUNCTION__, retval);
+
+ return retval;
+}
+
+Error
+NativeRegisterContext::SetPC (lldb::addr_t pc)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ return WriteRegisterFromUnsigned (reg, pc);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetSP (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+Error
+NativeRegisterContext::SetSP (lldb::addr_t sp)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ return WriteRegisterFromUnsigned (reg, sp);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetFP (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+Error
+NativeRegisterContext::SetFP (lldb::addr_t fp)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ return WriteRegisterFromUnsigned (reg, fp);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetReturnAddress (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetFlags (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+
+lldb::addr_t
+NativeRegisterContext::ReadRegisterAsUnsigned (uint32_t reg, lldb::addr_t fail_value)
+{
+ if (reg != LLDB_INVALID_REGNUM)
+ return ReadRegisterAsUnsigned (GetRegisterInfoAtIndex (reg), fail_value);
+ return fail_value;
+}
+
+uint64_t
+NativeRegisterContext::ReadRegisterAsUnsigned (const RegisterInfo *reg_info, lldb::addr_t fail_value)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ if (reg_info)
+ {
+ RegisterValue value;
+ Error error = ReadRegister (reg_info, value);
+ if (error.Success ())
+ {
+ if (log)
+ log->Printf ("NativeRegisterContext::%s ReadRegister() succeeded, value %" PRIu64, __FUNCTION__, value.GetAsUInt64());
+ return value.GetAsUInt64();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeRegisterContext::%s ReadRegister() failed, error %s", __FUNCTION__, error.AsCString ());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeRegisterContext::%s ReadRegister() null reg_info", __FUNCTION__);
+ }
+ return fail_value;
+}
+
+Error
+NativeRegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval)
+{
+ if (reg == LLDB_INVALID_REGNUM)
+ return Error ("NativeRegisterContext::%s (): reg is invalid", __FUNCTION__);
+ return WriteRegisterFromUnsigned (GetRegisterInfoAtIndex (reg), uval);
+}
+
+Error
+NativeRegisterContext::WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval)
+{
+ assert (reg_info);
+ if (!reg_info)
+ return Error ("reg_info is nullptr");
+
+ RegisterValue value;
+ if (!value.SetUInt(uval, reg_info->byte_size))
+ return Error ("RegisterValue::SetUInt () failed");
+
+ return WriteRegister (reg_info, value);
+}
+
+lldb::tid_t
+NativeRegisterContext::GetThreadID() const
+{
+ return m_thread.GetID();
+}
+
+uint32_t
+NativeRegisterContext::NumSupportedHardwareBreakpoints ()
+{
+ return 0;
+}
+
+uint32_t
+NativeRegisterContext::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+NativeRegisterContext::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+ return false;
+}
+
+
+uint32_t
+NativeRegisterContext::NumSupportedHardwareWatchpoints ()
+{
+ return 0;
+}
+
+uint32_t
+NativeRegisterContext::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
+{
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+NativeRegisterContext::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+NativeRegisterContext::HardwareSingleStep (bool enable)
+{
+ return false;
+}
+
+Error
+NativeRegisterContext::ReadRegisterValueFromMemory (
+ const RegisterInfo *reg_info,
+ lldb::addr_t src_addr,
+ lldb::addr_t src_len,
+ RegisterValue &reg_value)
+{
+ Error error;
+ if (reg_info == nullptr)
+ {
+ error.SetErrorString ("invalid register info argument.");
+ return error;
+ }
+
+
+ // Moving from addr into a register
+ //
+ // Case 1: src_len == dst_len
+ //
+ // |AABBCCDD| Address contents
+ // |AABBCCDD| Register contents
+ //
+ // Case 2: src_len > dst_len
+ //
+ // Error! (The register should always be big enough to hold the data)
+ //
+ // Case 3: src_len < dst_len
+ //
+ // |AABB| Address contents
+ // |AABB0000| Register contents [on little-endian hardware]
+ // |0000AABB| Register contents [on big-endian hardware]
+ if (src_len > RegisterValue::kMaxRegisterByteSize)
+ {
+ error.SetErrorString ("register too small to receive memory data");
+ return error;
+ }
+
+ const lldb::addr_t dst_len = reg_info->byte_size;
+
+ if (src_len > dst_len)
+ {
+ error.SetErrorStringWithFormat("%" PRIu64 " bytes is too big to store in register %s (%" PRIu64 " bytes)", src_len, reg_info->name, dst_len);
+ return error;
+ }
+
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (!process_sp)
+ {
+ error.SetErrorString("invalid process");
+ return error;
+ }
+
+ uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+ // Read the memory
+ lldb::addr_t bytes_read;
+ error = process_sp->ReadMemory (src_addr, src, src_len, bytes_read);
+ if (error.Fail ())
+ return error;
+
+ // Make sure the memory read succeeded...
+ if (bytes_read != src_len)
+ {
+ // This might happen if we read _some_ bytes but not all
+ error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " bytes", bytes_read, src_len);
+ return error;
+ }
+
+ // We now have a memory buffer that contains the part or all of the register
+ // value. Set the register value using this memory data.
+ // TODO: we might need to add a parameter to this function in case the byte
+ // order of the memory data doesn't match the process. For now we are assuming
+ // they are the same.
+ lldb::ByteOrder byte_order;
+ if (!process_sp->GetByteOrder (byte_order))
+ {
+ error.SetErrorString ( "NativeProcessProtocol::GetByteOrder () failed");
+ return error;
+ }
+
+ reg_value.SetFromMemoryData (
+ reg_info,
+ src,
+ src_len,
+ byte_order,
+ error);
+
+ return error;
+}
+
+Error
+NativeRegisterContext::WriteRegisterValueToMemory (
+ const RegisterInfo *reg_info,
+ lldb::addr_t dst_addr,
+ lldb::addr_t dst_len,
+ const RegisterValue &reg_value)
+{
+
+ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+ Error error;
+
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (process_sp)
+ {
+
+ // TODO: we might need to add a parameter to this function in case the byte
+ // order of the memory data doesn't match the process. For now we are assuming
+ // they are the same.
+ lldb::ByteOrder byte_order;
+ if (!process_sp->GetByteOrder (byte_order))
+ return Error ("NativeProcessProtocol::GetByteOrder () failed");
+
+ const lldb::addr_t bytes_copied = reg_value.GetAsMemoryData (
+ reg_info,
+ dst,
+ dst_len,
+ byte_order,
+ error);
+
+ if (error.Success())
+ {
+ if (bytes_copied == 0)
+ {
+ error.SetErrorString("byte copy failed.");
+ }
+ else
+ {
+ lldb::addr_t bytes_written;
+ error = process_sp->WriteMemory (dst_addr, dst, bytes_copied, bytes_written);
+ if (error.Fail ())
+ return error;
+
+ if (bytes_written != bytes_copied)
+ {
+ // This might happen if we read _some_ bytes but not all
+ error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 " bytes", bytes_written, bytes_copied);
+ }
+ }
+ }
+ }
+ else
+ error.SetErrorString("invalid process");
+
+ return error;
+}
+
+uint32_t
+NativeRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const
+{
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert (kind < kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+
diff --git a/source/Target/NativeRegisterContextRegisterInfo.cpp b/source/Target/NativeRegisterContextRegisterInfo.cpp
new file mode 100644
index 000000000000..e37014546646
--- /dev/null
+++ b/source/Target/NativeRegisterContextRegisterInfo.cpp
@@ -0,0 +1,44 @@
+//===-- NativeRegisterContex.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-types.h"
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Target/NativeRegisterContextRegisterInfo.h"
+
+using namespace lldb_private;
+
+NativeRegisterContextRegisterInfo::NativeRegisterContextRegisterInfo (NativeThreadProtocol &thread,
+ uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info_interface) :
+ NativeRegisterContext (thread, concrete_frame_idx),
+ m_register_info_interface_up (register_info_interface)
+{
+ assert (register_info_interface && "null register_info_interface");
+}
+
+uint32_t
+NativeRegisterContextRegisterInfo::GetRegisterCount () const
+{
+ return m_register_info_interface_up->GetRegisterCount ();
+}
+
+const RegisterInfo *
+NativeRegisterContextRegisterInfo::GetRegisterInfoAtIndex (uint32_t reg_index) const
+{
+ if (reg_index <= GetRegisterCount ())
+ return m_register_info_interface_up->GetRegisterInfo () + reg_index;
+ else
+ return nullptr;
+}
+
+const RegisterInfoInterface&
+NativeRegisterContextRegisterInfo::GetRegisterInfoInterface () const
+{
+ return *m_register_info_interface_up;
+}
diff --git a/source/Target/ObjCLanguageRuntime.cpp b/source/Target/ObjCLanguageRuntime.cpp
index 64ddfcc6c796..1f2abd876c84 100644
--- a/source/Target/ObjCLanguageRuntime.cpp
+++ b/source/Target/ObjCLanguageRuntime.cpp
@@ -602,4 +602,27 @@ ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa)
}
+ClangASTType
+ObjCLanguageRuntime::EncodingToType::RealizeType (const char* name, bool allow_unknownanytype)
+{
+ if (m_scratch_ast_ctx_ap)
+ return RealizeType(*m_scratch_ast_ctx_ap, name, allow_unknownanytype);
+ return ClangASTType();
+}
+
+ClangASTType
+ObjCLanguageRuntime::EncodingToType::RealizeType (ClangASTContext& ast_ctx, const char* name, bool allow_unknownanytype)
+{
+ clang::ASTContext *clang_ast = ast_ctx.getASTContext();
+ if (!clang_ast)
+ return ClangASTType();
+ return RealizeType(*clang_ast, name, allow_unknownanytype);
+}
+
+ObjCLanguageRuntime::EncodingToType::~EncodingToType() {}
+ObjCLanguageRuntime::EncodingToTypeSP
+ObjCLanguageRuntime::GetEncodingToType ()
+{
+ return nullptr;
+}
diff --git a/source/Target/PathMappingList.cpp b/source/Target/PathMappingList.cpp
index db23a0b27130..2fd517829b8c 100644
--- a/source/Target/PathMappingList.cpp
+++ b/source/Target/PathMappingList.cpp
@@ -132,7 +132,7 @@ PathMappingList::Replace (const ConstString &path,
}
bool
-PathMappingList::Remove (off_t index, bool notify)
+PathMappingList::Remove (size_t index, bool notify)
{
if (index >= m_pairs.size())
return false;
@@ -161,7 +161,7 @@ PathMappingList::Dump (Stream *s, int pair_index)
}
else
{
- if (pair_index < numPairs)
+ if (static_cast<unsigned int>(pair_index) < numPairs)
s->Printf("%s -> %s",
m_pairs[pair_index].first.GetCString(), m_pairs[pair_index].second.GetCString());
}
diff --git a/source/Target/Platform.cpp b/source/Target/Platform.cpp
index d6010fb22a5b..fe73be2d05b9 100644
--- a/source/Target/Platform.cpp
+++ b/source/Target/Platform.cpp
@@ -19,7 +19,9 @@
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Utils.h"
@@ -91,7 +93,7 @@ Platform::GetFileWithUUID (const FileSpec &platform_file,
}
FileSpecList
-Platform::LocateExecutableScriptingResources (Target *target, Module &module)
+Platform::LocateExecutableScriptingResources (Target *target, Module &module, Stream* feedback_stream)
{
return FileSpecList();
}
@@ -257,11 +259,12 @@ Platform::Platform (bool is_host) :
m_ssh_opts (),
m_ignores_remote_hostname (false),
m_trap_handlers(),
- m_calculated_trap_handlers (false)
+ m_calculated_trap_handlers (false),
+ m_trap_handler_mutex()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Platform::Platform()", this);
+ log->Printf ("%p Platform::Platform()", static_cast<void*>(this));
}
//------------------------------------------------------------------
@@ -274,7 +277,7 @@ Platform::~Platform()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Platform::~Platform()", this);
+ log->Printf ("%p Platform::~Platform()", static_cast<void*>(this));
}
void
@@ -347,9 +350,7 @@ Platform::GetOSVersion (uint32_t &major,
if (!success)
{
// We have a local host platform
- success = Host::GetOSVersion (m_major_os_version,
- m_minor_os_version,
- m_update_os_version);
+ success = HostInfo::GetOSVersion(m_major_os_version, m_minor_os_version, m_update_os_version);
m_os_version_set_while_connected = success;
}
}
@@ -396,8 +397,14 @@ Platform::GetOSVersion (uint32_t &major,
bool
Platform::GetOSBuildString (std::string &s)
{
+ s.clear();
+
if (IsHost())
- return Host::GetOSBuildString (s);
+#if !defined(__linux__)
+ return HostInfo::GetOSBuildString(s);
+#else
+ return false;
+#endif
else
return GetRemoteOSBuildString (s);
}
@@ -406,7 +413,11 @@ bool
Platform::GetOSKernelDescription (std::string &s)
{
if (IsHost())
- return Host::GetOSKernelDescription (s);
+#if !defined(__linux__)
+ return HostInfo::GetOSKernelDescription(s);
+#else
+ return false;
+#endif
else
return GetRemoteOSKernelDescription (s);
}
@@ -493,8 +504,8 @@ RecurseCopy_Callback (void *baton,
dst_file.GetFilename() = src.GetFilename();
char buf[PATH_MAX];
-
- rc_baton->error = Host::Readlink (src.GetPath().c_str(), buf, sizeof(buf));
+
+ rc_baton->error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf));
if (rc_baton->error.Fail())
return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
@@ -526,6 +537,7 @@ RecurseCopy_Callback (void *baton,
case FileSpec::eFileTypeInvalid:
case FileSpec::eFileTypeOther:
case FileSpec::eFileTypeUnknown:
+ default:
rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s", src.GetPath().c_str());
return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
break;
@@ -647,7 +659,7 @@ Platform::Install (const FileSpec& src, const FileSpec& dst)
if (GetFileExists (fixed_dst))
Unlink (fixed_dst.GetPath().c_str());
char buf[PATH_MAX];
- error = Host::Readlink(src.GetPath().c_str(), buf, sizeof(buf));
+ error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf));
if (error.Success())
error = CreateSymlink(dst.GetPath().c_str(), buf);
}
@@ -699,7 +711,7 @@ Error
Platform::MakeDirectory (const char *path, uint32_t permissions)
{
if (IsHost())
- return Host::MakeDirectory (path, permissions);
+ return FileSystem::MakeDirectory(path, permissions);
else
{
Error error;
@@ -712,7 +724,7 @@ Error
Platform::GetFilePermissions (const char *path, uint32_t &file_permissions)
{
if (IsHost())
- return Host::GetFilePermissions(path, file_permissions);
+ return FileSystem::GetFilePermissions(path, file_permissions);
else
{
Error error;
@@ -725,7 +737,7 @@ Error
Platform::SetFilePermissions (const char *path, uint32_t file_permissions)
{
if (IsHost())
- return Host::SetFilePermissions(path, file_permissions);
+ return FileSystem::SetFilePermissions(path, file_permissions);
else
{
Error error;
@@ -744,7 +756,7 @@ const char *
Platform::GetHostname ()
{
if (IsHost())
- return "localhost";
+ return "127.0.0.1";
if (m_name.empty())
return NULL;
@@ -764,30 +776,34 @@ Platform::SetRemoteWorkingDirectory(const ConstString &path)
const char *
Platform::GetUserName (uint32_t uid)
{
+#if !defined(LLDB_DISABLE_POSIX)
const char *user_name = GetCachedUserName(uid);
if (user_name)
return user_name;
if (IsHost())
{
std::string name;
- if (Host::GetUserName(uid, name))
+ if (HostInfo::LookupUserName(uid, name))
return SetCachedUserName (uid, name.c_str(), name.size());
}
+#endif
return NULL;
}
const char *
Platform::GetGroupName (uint32_t gid)
{
+#if !defined(LLDB_DISABLE_POSIX)
const char *group_name = GetCachedGroupName(gid);
if (group_name)
return group_name;
if (IsHost())
{
std::string name;
- if (Host::GetGroupName(gid, name))
+ if (HostInfo::LookupGroupName(gid, name))
return SetCachedGroupName (gid, name.c_str(), name.size());
}
+#endif
return NULL;
}
@@ -798,8 +814,8 @@ Platform::SetOSVersion (uint32_t major,
{
if (IsHost())
{
- // We don't need anyone setting the OS version for the host platform,
- // we should be able to figure it out by calling Host::GetOSVersion(...).
+ // We don't need anyone setting the OS version for the host platform,
+ // we should be able to figure it out by calling HostInfo::GetOSVersion(...).
return false;
}
else
@@ -902,7 +918,7 @@ Platform::GetSystemArchitecture()
if (!m_system_arch.IsValid())
{
// We have a local host platform
- m_system_arch = Host::GetArchitecture();
+ m_system_arch = HostInfo::GetArchitecture();
m_system_arch_set_while_connected = m_system_arch.IsValid();
}
}
@@ -1180,11 +1196,32 @@ Platform::CalculateMD5 (const FileSpec& file_spec,
uint64_t &high)
{
if (IsHost())
- return Host::CalculateMD5(file_spec, low, high);
+ return FileSystem::CalculateMD5(file_spec, low, high);
else
return false;
}
+Error
+Platform::LaunchNativeProcess (
+ ProcessLaunchInfo &launch_info,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp)
+{
+ // Platforms should override this implementation if they want to
+ // support lldb-gdbserver.
+ return Error("unimplemented");
+}
+
+Error
+Platform::AttachNativeProcess (lldb::pid_t pid,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp)
+{
+ // Platforms should override this implementation if they want to
+ // support lldb-gdbserver.
+ return Error("unimplemented");
+}
+
void
Platform::SetLocalCacheDirectory (const char* local)
{
@@ -1200,23 +1237,23 @@ Platform::GetLocalCacheDirectory ()
static OptionDefinition
g_rsync_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "rsync" , 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Enable rsync." },
- { LLDB_OPT_SET_ALL, false, "rsync-opts" , 'R', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCommandName , "Platform-specific options required for rsync to work." },
- { LLDB_OPT_SET_ALL, false, "rsync-prefix" , 'P', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCommandName , "Platform-specific rsync prefix put before the remote path." },
- { LLDB_OPT_SET_ALL, false, "ignore-remote-hostname" , 'i', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Do not automatically fill in the remote hostname when composing the rsync command." },
+ { LLDB_OPT_SET_ALL, false, "rsync" , 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Enable rsync." },
+ { LLDB_OPT_SET_ALL, false, "rsync-opts" , 'R', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName , "Platform-specific options required for rsync to work." },
+ { LLDB_OPT_SET_ALL, false, "rsync-prefix" , 'P', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName , "Platform-specific rsync prefix put before the remote path." },
+ { LLDB_OPT_SET_ALL, false, "ignore-remote-hostname" , 'i', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Do not automatically fill in the remote hostname when composing the rsync command." },
};
static OptionDefinition
g_ssh_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "ssh" , 's', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Enable SSH." },
- { LLDB_OPT_SET_ALL, false, "ssh-opts" , 'S', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCommandName , "Platform-specific options required for SSH to work." },
+ { LLDB_OPT_SET_ALL, false, "ssh" , 's', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Enable SSH." },
+ { LLDB_OPT_SET_ALL, false, "ssh-opts" , 'S', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName , "Platform-specific options required for SSH to work." },
};
static OptionDefinition
g_caching_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "local-cache-dir" , 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypePath , "Path in which to store local copies of files." },
+ { LLDB_OPT_SET_ALL, false, "local-cache-dir" , 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePath , "Path in which to store local copies of files." },
};
OptionGroupPlatformRSync::OptionGroupPlatformRSync ()
@@ -1398,8 +1435,12 @@ Platform::GetTrapHandlerSymbolNames ()
{
if (!m_calculated_trap_handlers)
{
- CalculateTrapHandlerSymbolNames();
- m_calculated_trap_handlers = true;
+ Mutex::Locker locker (m_trap_handler_mutex);
+ if (!m_calculated_trap_handlers)
+ {
+ CalculateTrapHandlerSymbolNames();
+ m_calculated_trap_handlers = true;
+ }
}
return m_trap_handlers;
}
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp
index 1256ad34c975..a1049787d821 100644
--- a/source/Target/Process.cpp
+++ b/source/Target/Process.cpp
@@ -27,9 +27,11 @@
#include "lldb/Expression/ClangUserExpression.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/Pipe.h"
#include "lldb/Host/Terminal.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/JITLoader.h"
#include "lldb/Target/OperatingSystem.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/CPPLanguageRuntime.h"
@@ -45,10 +47,6 @@
#include "lldb/Target/ThreadPlanBase.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
-#ifndef LLDB_DISABLE_POSIX
-#include <spawn.h>
-#endif
-
using namespace lldb;
using namespace lldb_private;
@@ -82,7 +80,7 @@ public:
virtual const Property *
GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
{
- // When gettings the value for a key from the process options, we will always
+ // When getting the value for a key from the process options, we will always
// try and grab the setting from the current process if there is one. Else we just
// use the one from this instance.
if (exe_ctx)
@@ -321,8 +319,8 @@ ProcessInstanceInfo::DumpTableHeader (Stream &s, Platform *platform, bool show_a
}
else
{
- s.Printf ("PID PARENT USER ARCH %s\n", label);
- s.PutCString ("====== ====== ========== ======= ============================\n");
+ s.Printf ("PID PARENT USER TRIPLE %s\n", label);
+ s.PutCString ("====== ====== ========== ======================== ============================\n");
}
}
@@ -364,10 +362,9 @@ ProcessInstanceInfo::DumpAsTableRow (Stream &s, Platform *platform, bool show_ar
}
else
{
- s.Printf ("%-10s %-7d %s ",
+ s.Printf ("%-10s %-24s ",
platform->GetUserName (m_euid),
- (int)m_arch.GetTriple().getArchName().size(),
- m_arch.GetTriple().getArchName().data());
+ m_arch.IsValid() ? m_arch.GetTriple().str().c_str() : "");
}
if (verbose || show_args)
@@ -392,361 +389,6 @@ ProcessInstanceInfo::DumpAsTableRow (Stream &s, Platform *platform, bool show_ar
}
}
-
-void
-ProcessInfo::SetArguments (char const **argv, bool first_arg_is_executable)
-{
- m_arguments.SetArguments (argv);
-
- // Is the first argument the executable?
- if (first_arg_is_executable)
- {
- const char *first_arg = m_arguments.GetArgumentAtIndex (0);
- if (first_arg)
- {
- // Yes the first argument is an executable, set it as the executable
- // in the launch options. Don't resolve the file path as the path
- // could be a remote platform path
- const bool resolve = false;
- m_executable.SetFile(first_arg, resolve);
- }
- }
-}
-void
-ProcessInfo::SetArguments (const Args& args, bool first_arg_is_executable)
-{
- // Copy all arguments
- m_arguments = args;
-
- // Is the first argument the executable?
- if (first_arg_is_executable)
- {
- const char *first_arg = m_arguments.GetArgumentAtIndex (0);
- if (first_arg)
- {
- // Yes the first argument is an executable, set it as the executable
- // in the launch options. Don't resolve the file path as the path
- // could be a remote platform path
- const bool resolve = false;
- m_executable.SetFile(first_arg, resolve);
- }
- }
-}
-
-void
-ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
-{
- // If notthing was specified, then check the process for any default
- // settings that were set with "settings set"
- if (m_file_actions.empty())
- {
- if (m_flags.Test(eLaunchFlagDisableSTDIO))
- {
- AppendSuppressFileAction (STDIN_FILENO , true, false);
- AppendSuppressFileAction (STDOUT_FILENO, false, true);
- AppendSuppressFileAction (STDERR_FILENO, false, true);
- }
- else
- {
- // Check for any values that might have gotten set with any of:
- // (lldb) settings set target.input-path
- // (lldb) settings set target.output-path
- // (lldb) settings set target.error-path
- FileSpec in_path;
- FileSpec out_path;
- FileSpec err_path;
- if (target)
- {
- in_path = target->GetStandardInputPath();
- out_path = target->GetStandardOutputPath();
- err_path = target->GetStandardErrorPath();
- }
-
- if (in_path || out_path || err_path)
- {
- char path[PATH_MAX];
- if (in_path && in_path.GetPath(path, sizeof(path)))
- AppendOpenFileAction(STDIN_FILENO, path, true, false);
-
- if (out_path && out_path.GetPath(path, sizeof(path)))
- AppendOpenFileAction(STDOUT_FILENO, path, false, true);
-
- if (err_path && err_path.GetPath(path, sizeof(path)))
- AppendOpenFileAction(STDERR_FILENO, path, false, true);
- }
- else if (default_to_use_pty)
- {
- if (m_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, NULL, 0))
- {
- const char *slave_path = m_pty.GetSlaveName (NULL, 0);
- AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
- AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
- AppendOpenFileAction(STDERR_FILENO, slave_path, false, true);
- }
- }
- }
- }
-}
-
-
-bool
-ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
- bool localhost,
- bool will_debug,
- bool first_arg_is_full_shell_command,
- int32_t num_resumes)
-{
- error.Clear();
-
- if (GetFlags().Test (eLaunchFlagLaunchInShell))
- {
- const char *shell_executable = GetShell();
- if (shell_executable)
- {
- char shell_resolved_path[PATH_MAX];
-
- if (localhost)
- {
- FileSpec shell_filespec (shell_executable, true);
-
- if (!shell_filespec.Exists())
- {
- // Resolve the path in case we just got "bash", "sh" or "tcsh"
- if (!shell_filespec.ResolveExecutableLocation ())
- {
- error.SetErrorStringWithFormat("invalid shell path '%s'", shell_executable);
- return false;
- }
- }
- shell_filespec.GetPath (shell_resolved_path, sizeof(shell_resolved_path));
- shell_executable = shell_resolved_path;
- }
-
- const char **argv = GetArguments().GetConstArgumentVector ();
- if (argv == NULL || argv[0] == NULL)
- return false;
- Args shell_arguments;
- std::string safe_arg;
- shell_arguments.AppendArgument (shell_executable);
- shell_arguments.AppendArgument ("-c");
- StreamString shell_command;
- if (will_debug)
- {
- // Add a modified PATH environment variable in case argv[0]
- // is a relative path
- const char *argv0 = argv[0];
- if (argv0 && (argv0[0] != '/' && argv0[0] != '~'))
- {
- // We have a relative path to our executable which may not work if
- // we just try to run "a.out" (without it being converted to "./a.out")
- const char *working_dir = GetWorkingDirectory();
- // Be sure to put quotes around PATH's value in case any paths have spaces...
- std::string new_path("PATH=\"");
- const size_t empty_path_len = new_path.size();
-
- if (working_dir && working_dir[0])
- {
- new_path += working_dir;
- }
- else
- {
- char current_working_dir[PATH_MAX];
- const char *cwd = getcwd(current_working_dir, sizeof(current_working_dir));
- if (cwd && cwd[0])
- new_path += cwd;
- }
- const char *curr_path = getenv("PATH");
- if (curr_path)
- {
- if (new_path.size() > empty_path_len)
- new_path += ':';
- new_path += curr_path;
- }
- new_path += "\" ";
- shell_command.PutCString(new_path.c_str());
- }
-
- shell_command.PutCString ("exec");
-
- // Only Apple supports /usr/bin/arch being able to specify the architecture
- if (GetArchitecture().IsValid())
- {
- shell_command.Printf(" /usr/bin/arch -arch %s", GetArchitecture().GetArchitectureName());
- // Set the resume count to 2:
- // 1 - stop in shell
- // 2 - stop in /usr/bin/arch
- // 3 - then we will stop in our program
- SetResumeCount(num_resumes + 1);
- }
- else
- {
- // Set the resume count to 1:
- // 1 - stop in shell
- // 2 - then we will stop in our program
- SetResumeCount(num_resumes);
- }
- }
-
- if (first_arg_is_full_shell_command)
- {
- // There should only be one argument that is the shell command itself to be used as is
- if (argv[0] && !argv[1])
- shell_command.Printf("%s", argv[0]);
- else
- return false;
- }
- else
- {
- for (size_t i=0; argv[i] != NULL; ++i)
- {
- const char *arg = Args::GetShellSafeArgument (argv[i], safe_arg);
- shell_command.Printf(" %s", arg);
- }
- }
- shell_arguments.AppendArgument (shell_command.GetString().c_str());
- m_executable.SetFile(shell_executable, false);
- m_arguments = shell_arguments;
- return true;
- }
- else
- {
- error.SetErrorString ("invalid shell path");
- }
- }
- else
- {
- error.SetErrorString ("not launching in shell");
- }
- return false;
-}
-
-
-bool
-ProcessLaunchInfo::FileAction::Open (int fd, const char *path, bool read, bool write)
-{
- if ((read || write) && fd >= 0 && path && path[0])
- {
- m_action = eFileActionOpen;
- m_fd = fd;
- if (read && write)
- m_arg = O_NOCTTY | O_CREAT | O_RDWR;
- else if (read)
- m_arg = O_NOCTTY | O_RDONLY;
- else
- m_arg = O_NOCTTY | O_CREAT | O_WRONLY;
- m_path.assign (path);
- return true;
- }
- else
- {
- Clear();
- }
- return false;
-}
-
-bool
-ProcessLaunchInfo::FileAction::Close (int fd)
-{
- Clear();
- if (fd >= 0)
- {
- m_action = eFileActionClose;
- m_fd = fd;
- }
- return m_fd >= 0;
-}
-
-
-bool
-ProcessLaunchInfo::FileAction::Duplicate (int fd, int dup_fd)
-{
- Clear();
- if (fd >= 0 && dup_fd >= 0)
- {
- m_action = eFileActionDuplicate;
- m_fd = fd;
- m_arg = dup_fd;
- }
- return m_fd >= 0;
-}
-
-
-
-#ifndef LLDB_DISABLE_POSIX
-bool
-ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (void *_file_actions,
- const FileAction *info,
- Log *log,
- Error& error)
-{
- if (info == NULL)
- return false;
-
- posix_spawn_file_actions_t *file_actions = reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions);
-
- switch (info->m_action)
- {
- case eFileActionNone:
- error.Clear();
- break;
-
- case eFileActionClose:
- if (info->m_fd == -1)
- error.SetErrorString ("invalid fd for posix_spawn_file_actions_addclose(...)");
- else
- {
- error.SetError (::posix_spawn_file_actions_addclose (file_actions, info->m_fd),
- eErrorTypePOSIX);
- if (log && (error.Fail() || log))
- error.PutToLog(log, "posix_spawn_file_actions_addclose (action=%p, fd=%i)",
- file_actions, info->m_fd);
- }
- break;
-
- case eFileActionDuplicate:
- if (info->m_fd == -1)
- error.SetErrorString ("invalid fd for posix_spawn_file_actions_adddup2(...)");
- else if (info->m_arg == -1)
- error.SetErrorString ("invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
- else
- {
- error.SetError (::posix_spawn_file_actions_adddup2 (file_actions, info->m_fd, info->m_arg),
- eErrorTypePOSIX);
- if (log && (error.Fail() || log))
- error.PutToLog(log, "posix_spawn_file_actions_adddup2 (action=%p, fd=%i, dup_fd=%i)",
- file_actions, info->m_fd, info->m_arg);
- }
- break;
-
- case eFileActionOpen:
- if (info->m_fd == -1)
- error.SetErrorString ("invalid fd in posix_spawn_file_actions_addopen(...)");
- else
- {
- int oflag = info->m_arg;
-
- mode_t mode = 0;
-
- if (oflag & O_CREAT)
- mode = 0640;
-
- error.SetError (::posix_spawn_file_actions_addopen (file_actions,
- info->m_fd,
- info->m_path.c_str(),
- oflag,
- mode),
- eErrorTypePOSIX);
- if (error.Fail() || log)
- error.PutToLog(log,
- "posix_spawn_file_actions_addopen (action=%p, fd=%i, path='%s', oflag=%i, mode=%i)",
- file_actions, info->m_fd, info->m_path.c_str(), oflag, mode);
- }
- break;
- }
- return error.Success();
-}
-#endif
-
Error
ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)
{
@@ -760,45 +402,44 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
break;
case 'i': // STDIN for read only
- {
- ProcessLaunchInfo::FileAction action;
- if (action.Open (STDIN_FILENO, option_arg, true, false))
- launch_info.AppendFileAction (action);
- }
+ {
+ FileAction action;
+ if (action.Open (STDIN_FILENO, option_arg, true, false))
+ launch_info.AppendFileAction (action);
break;
+ }
case 'o': // Open STDOUT for write only
- {
- ProcessLaunchInfo::FileAction action;
- if (action.Open (STDOUT_FILENO, option_arg, false, true))
- launch_info.AppendFileAction (action);
- }
+ {
+ FileAction action;
+ if (action.Open (STDOUT_FILENO, option_arg, false, true))
+ launch_info.AppendFileAction (action);
break;
+ }
case 'e': // STDERR for write only
- {
- ProcessLaunchInfo::FileAction action;
- if (action.Open (STDERR_FILENO, option_arg, false, true))
- launch_info.AppendFileAction (action);
- }
+ {
+ FileAction action;
+ if (action.Open (STDERR_FILENO, option_arg, false, true))
+ launch_info.AppendFileAction (action);
break;
-
+ }
case 'p': // Process plug-in name
launch_info.SetProcessPluginName (option_arg);
break;
case 'n': // Disable STDIO
- {
- ProcessLaunchInfo::FileAction action;
- if (action.Open (STDIN_FILENO, "/dev/null", true, false))
- launch_info.AppendFileAction (action);
- if (action.Open (STDOUT_FILENO, "/dev/null", false, true))
- launch_info.AppendFileAction (action);
- if (action.Open (STDERR_FILENO, "/dev/null", false, true))
- launch_info.AppendFileAction (action);
- }
+ {
+ FileAction action;
+ if (action.Open (STDIN_FILENO, "/dev/null", true, false))
+ launch_info.AppendFileAction (action);
+ if (action.Open (STDOUT_FILENO, "/dev/null", false, true))
+ launch_info.AppendFileAction (action);
+ if (action.Open (STDERR_FILENO, "/dev/null", false, true))
+ launch_info.AppendFileAction (action);
break;
+ }
case 'w':
launch_info.SetWorkingDirectory (option_arg);
@@ -813,11 +454,18 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
launch_info.GetArchitecture().SetTriple (option_arg);
break;
- case 'A':
- launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+ case 'A': // Disable ASLR.
+ {
+ bool success;
+ const bool disable_aslr_arg = Args::StringToBoolean (option_arg, true, &success);
+ if (success)
+ disable_aslr = disable_aslr_arg ? eLazyBoolYes : eLazyBoolNo;
+ else
+ error.SetErrorStringWithFormat ("Invalid boolean value for disable-aslr option: '%s'", option_arg ? option_arg : "<null>");
break;
-
- case 'c':
+ }
+
+ case 'c':
if (option_arg && option_arg[0])
launch_info.SetShell (option_arg);
else
@@ -831,7 +479,6 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
default:
error.SetErrorStringWithFormat("unrecognized short option character '%c'", short_option);
break;
-
}
return error;
}
@@ -839,23 +486,23 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
OptionDefinition
ProcessLaunchCommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_ALL, false, "stop-at-entry", 's', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Stop at the entry point of the program when launching a process."},
-{ LLDB_OPT_SET_ALL, false, "disable-aslr", 'A', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Disable address space layout randomization when launching a process."},
-{ LLDB_OPT_SET_ALL, false, "plugin", 'p', OptionParser::eRequiredArgument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
-{ LLDB_OPT_SET_ALL, false, "working-dir", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeDirectoryName, "Set the current working directory to <path> when running the inferior."},
-{ LLDB_OPT_SET_ALL, false, "arch", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeArchitecture, "Set the architecture for the process to launch when ambiguous."},
-{ LLDB_OPT_SET_ALL, false, "environment", 'v', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNone, "Specify an environment variable name/value string (--environment NAME=VALUE). Can be specified multiple times for subsequent environment entries."},
-{ LLDB_OPT_SET_ALL, false, "shell", 'c', OptionParser::eOptionalArgument, NULL, 0, eArgTypeFilename, "Run the process in a shell (not supported on all platforms)."},
+{ LLDB_OPT_SET_ALL, false, "stop-at-entry", 's', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Stop at the entry point of the program when launching a process."},
+{ LLDB_OPT_SET_ALL, false, "disable-aslr", 'A', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "Set whether to disable address space layout randomization when launching a process."},
+{ 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_ALL, false, "working-dir", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeDirectoryName, "Set the current working directory to <path> when running the inferior."},
+{ LLDB_OPT_SET_ALL, false, "arch", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeArchitecture, "Set the architecture for the process to launch when ambiguous."},
+{ LLDB_OPT_SET_ALL, false, "environment", 'v', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeNone, "Specify an environment variable name/value string (--environment NAME=VALUE). Can be specified multiple times for subsequent environment entries."},
+{ LLDB_OPT_SET_ALL, false, "shell", 'c', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeFilename, "Run the process in a shell (not supported on all platforms)."},
-{ LLDB_OPT_SET_1 , false, "stdin", 'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename, "Redirect stdin for the process to <filename>."},
-{ LLDB_OPT_SET_1 , false, "stdout", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename, "Redirect stdout for the process to <filename>."},
-{ LLDB_OPT_SET_1 , false, "stderr", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename, "Redirect stderr for the process to <filename>."},
+{ LLDB_OPT_SET_1 , false, "stdin", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, "Redirect stdin for the process to <filename>."},
+{ LLDB_OPT_SET_1 , false, "stdout", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, "Redirect stdout for the process to <filename>."},
+{ LLDB_OPT_SET_1 , false, "stderr", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, "Redirect stderr for the process to <filename>."},
-{ LLDB_OPT_SET_2 , false, "tty", 't', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Start the process in a terminal (not supported on all platforms)."},
+{ LLDB_OPT_SET_2 , false, "tty", 't', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Start the process in a terminal (not supported on all platforms)."},
-{ LLDB_OPT_SET_3 , false, "no-stdio", 'n', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Do not set up for terminal I/O to go to running process."},
+{ LLDB_OPT_SET_3 , false, "no-stdio", 'n', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Do not set up for terminal I/O to go to running process."},
-{ 0 , false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ 0 , false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -1006,6 +653,13 @@ Process::GetStaticBroadcasterClass ()
// Process constructor
//----------------------------------------------------------------------
Process::Process(Target &target, Listener &listener) :
+ Process(target, listener, Host::GetUnixSignals ())
+{
+ // This constructor just delegates to the full Process constructor,
+ // defaulting to using the Host's UnixSignals.
+}
+
+Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_signals_sp) :
ProcessProperties (false),
UserID (LLDB_INVALID_PROCESS_ID),
Broadcaster (&(target.GetDebugger()), "lldb.process"),
@@ -1035,7 +689,7 @@ Process::Process(Target &target, Listener &listener) :
m_listener (listener),
m_breakpoint_site_list (),
m_dynamic_checkers_ap (),
- m_unix_signals (),
+ m_unix_signals_sp (unix_signals_sp),
m_abi_sp (),
m_process_input_reader (),
m_stdio_communication ("process.stdio"),
@@ -1044,6 +698,7 @@ Process::Process(Target &target, Listener &listener) :
m_stderr_data (),
m_profile_data_comm_mutex (Mutex::eMutexTypeRecursive),
m_profile_data (),
+ m_iohandler_sync (false),
m_memory_cache (*this),
m_allocated_memory_cache (*this),
m_should_detach (false),
@@ -1062,7 +717,10 @@ Process::Process(Target &target, Listener &listener) :
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Process::Process()", this);
+ log->Printf ("%p Process::Process()", static_cast<void*>(this));
+
+ if (!m_unix_signals_sp)
+ m_unix_signals_sp.reset (new UnixSignals ());
SetEventName (eBroadcastBitStateChanged, "state-changed");
SetEventName (eBroadcastBitInterrupt, "interrupt");
@@ -1089,6 +747,8 @@ Process::Process(Target &target, Listener &listener) :
eBroadcastInternalStateControlStop |
eBroadcastInternalStateControlPause |
eBroadcastInternalStateControlResume);
+ // We need something valid here, even if just the default UnixSignalsSP.
+ assert (m_unix_signals_sp && "null m_unix_signals_sp after initialization");
}
//----------------------------------------------------------------------
@@ -1098,7 +758,7 @@ Process::~Process()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Process::~Process()", this);
+ log->Printf ("%p Process::~Process()", static_cast<void*>(this));
StopPrivateStateThread();
}
@@ -1154,6 +814,7 @@ Process::Finalize()
m_os_ap.reset();
m_system_runtime_ap.reset();
m_dyld_ap.reset();
+ m_jit_loaders_ap.reset();
m_thread_list_real.Destroy();
m_thread_list.Destroy();
m_extended_thread_list.Destroy();
@@ -1241,6 +902,34 @@ Process::GetNextEvent (EventSP &event_sp)
return state;
}
+bool
+Process::SyncIOHandler (uint64_t timeout_msec)
+{
+ bool timed_out = false;
+
+ // don't sync (potentially context switch) in case where there is no process IO
+ if (m_process_input_reader)
+ {
+ TimeValue timeout = TimeValue::Now();
+ timeout.OffsetWithMicroSeconds(timeout_msec*1000);
+
+ m_iohandler_sync.WaitForValueEqualTo(true, &timeout, &timed_out);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if(log)
+ {
+ if(timed_out)
+ log->Printf ("Process::%s pid %" PRIu64 " (timeout=%" PRIu64 "ms): FAIL", __FUNCTION__, GetID (), timeout_msec);
+ else
+ log->Printf ("Process::%s pid %" PRIu64 ": SUCCESS", __FUNCTION__, GetID ());
+ }
+
+ // reset sync one-shot so it will be ready for next time
+ m_iohandler_sync.SetValue(false, eBroadcastNever);
+ }
+
+ return !timed_out;
+}
StateType
Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp_ptr, bool wait_always, Listener *hijack_listener)
@@ -1258,7 +947,8 @@ Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::%s (timeout = %p)", __FUNCTION__, timeout);
+ log->Printf ("Process::%s (timeout = %p)", __FUNCTION__,
+ static_cast<const void*>(timeout));
if (!wait_always &&
StateIsStoppedState(state, true) &&
@@ -1375,12 +1065,13 @@ Process::WaitForStateChangedEvents (const TimeValue *timeout, EventSP &event_sp,
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout);
+ log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__,
+ static_cast<const void*>(timeout));
Listener *listener = hijack_listener;
if (listener == NULL)
listener = &m_listener;
-
+
StateType state = eStateInvalid;
if (listener->WaitForEventForBroadcasterWithType (timeout,
this,
@@ -1395,8 +1086,7 @@ Process::WaitForStateChangedEvents (const TimeValue *timeout, EventSP &event_sp,
if (log)
log->Printf ("Process::%s (timeout = %p, event_sp) => %s",
- __FUNCTION__,
- timeout,
+ __FUNCTION__, static_cast<const void*>(timeout),
StateAsCString(state));
return state;
}
@@ -1435,7 +1125,8 @@ Process::WaitForStateChangedEventsPrivate (const TimeValue *timeout, EventSP &ev
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout);
+ log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__,
+ static_cast<const void*>(timeout));
StateType state = eStateInvalid;
if (m_private_state_listener.WaitForEventForBroadcasterWithType (timeout,
@@ -1449,12 +1140,9 @@ Process::WaitForStateChangedEventsPrivate (const TimeValue *timeout, EventSP &ev
// to the command-line, and that could disable the log, which would render the
// log we got above invalid.
if (log)
- {
- if (state == eStateInvalid)
- log->Printf ("Process::%s (timeout = %p, event_sp) => TIMEOUT", __FUNCTION__, timeout);
- else
- log->Printf ("Process::%s (timeout = %p, event_sp) => %s", __FUNCTION__, timeout, StateAsCString(state));
- }
+ log->Printf ("Process::%s (timeout = %p, event_sp) => %s",
+ __FUNCTION__, static_cast<const void *>(timeout),
+ state == eStateInvalid ? "TIMEOUT" : StateAsCString(state));
return state;
}
@@ -1464,7 +1152,8 @@ Process::WaitForEventsPrivate (const TimeValue *timeout, EventSP &event_sp, bool
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout);
+ log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__,
+ static_cast<const void*>(timeout));
if (control_only)
return m_private_state_listener.WaitForEventForBroadcaster(timeout, &m_private_state_control_broadcaster, event_sp);
@@ -1523,12 +1212,11 @@ Process::SetExitStatus (int status, const char *cstr)
DidExit ();
SetPrivateState (eStateExited);
- CancelWatchForSTDIN (true);
return true;
}
// This static callback can be used to watch for local child processes on
-// the current host. The the child process exits, the process will be
+// the current host. The child process exits, the process will be
// found in the global target list (we want to be completely sure that the
// lldb_private::Process doesn't go away before we can deliver the signal.
bool
@@ -1766,6 +1454,9 @@ Process::GetPrivateState ()
void
Process::SetPrivateState (StateType new_state)
{
+ if (m_finalize_called)
+ return;
+
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
bool state_changed = false;
@@ -1874,9 +1565,27 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)
expr_options.SetUnwindOnError(true);
expr_options.SetIgnoreBreakpoints(true);
expr_options.SetExecutionPolicy(eExecutionPolicyAlways);
+ expr_options.SetResultIsInternal(true);
+
StreamString expr;
- expr.Printf("dlopen (\"%s\", 2)", path);
- const char *prefix = "extern \"C\" void* dlopen (const char *path, int mode);\n";
+ expr.Printf(R"(
+ struct __lldb_dlopen_result { void *image_ptr; const char *error_str; } the_result;
+ the_result.image_ptr = dlopen ("%s", 2);
+ if (the_result.image_ptr == (void *) 0x0)
+ {
+ the_result.error_str = dlerror();
+ }
+ else
+ {
+ the_result.error_str = (const char *) 0x0;
+ }
+ the_result;
+ )",
+ path);
+ const char *prefix = R"(
+ extern "C" void* dlopen (const char *path, int mode);
+ extern "C" const char *dlerror (void);
+ )";
lldb::ValueObjectSP result_valobj_sp;
Error expr_error;
ClangUserExpression::Evaluate (exe_ctx,
@@ -1891,7 +1600,8 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)
if (error.Success())
{
Scalar scalar;
- if (result_valobj_sp->ResolveValue (scalar))
+ ValueObjectSP image_ptr_sp = result_valobj_sp->GetChildAtIndex(0, true);
+ if (image_ptr_sp && image_ptr_sp->ResolveValue (scalar))
{
addr_t image_ptr = scalar.ULongLong(LLDB_INVALID_ADDRESS);
if (image_ptr != 0 && image_ptr != LLDB_INVALID_ADDRESS)
@@ -1900,9 +1610,28 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)
m_image_tokens.push_back (image_ptr);
return image_token;
}
+ else if (image_ptr == 0)
+ {
+ ValueObjectSP error_str_sp = result_valobj_sp->GetChildAtIndex(1, true);
+ if (error_str_sp)
+ {
+ if (error_str_sp->IsCStringContainer(true))
+ {
+ StreamString s;
+ size_t num_chars = error_str_sp->ReadPointedString (s, error);
+ if (error.Success() && num_chars > 0)
+ {
+ error.Clear();
+ error.SetErrorStringWithFormat("dlopen error: %s", s.GetData());
+ }
+ }
+ }
+ }
}
}
}
+ else
+ error = expr_error;
}
}
}
@@ -2169,7 +1898,7 @@ Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardw
symbol->GetAddress().GetLoadAddress(&m_target),
owner->GetBreakpoint().GetID(),
owner->GetID(),
- error.AsCString() ? error.AsCString() : "unkown error");
+ error.AsCString() ? error.AsCString() : "unknown error");
return LLDB_INVALID_BREAK_ID;
}
Address resolved_address(load_addr);
@@ -2217,7 +1946,7 @@ Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardw
load_addr,
owner->GetBreakpoint().GetID(),
owner->GetID(),
- error.AsCString() ? error.AsCString() : "unkown error");
+ error.AsCString() ? error.AsCString() : "unknown error");
}
}
}
@@ -2379,7 +2108,7 @@ Process::DisableSoftwareBreakpoint (BreakpointSite *bp_site)
const uint8_t * const break_op = bp_site->GetTrapOpcodeBytes();
if (break_op_size > 0)
{
- // Clear a software breakoint instruction
+ // Clear a software breakpoint instruction
uint8_t curr_break_op[8];
assert (break_op_size <= sizeof(curr_break_op));
bool break_op_found = false;
@@ -2881,6 +2610,7 @@ Process::CanJIT ()
{
if (m_can_jit == eCanJITDontKnow)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
Error err;
uint64_t allocated_memory = AllocateMemory(8,
@@ -2888,9 +2618,17 @@ Process::CanJIT ()
err);
if (err.Success())
+ {
m_can_jit = eCanJITYes;
+ if (log)
+ log->Printf ("Process::%s pid %" PRIu64 " allocation test passed, CanJIT () is true", __FUNCTION__, GetID ());
+ }
else
+ {
m_can_jit = eCanJITNo;
+ if (log)
+ log->Printf ("Process::%s pid %" PRIu64 " allocation test failed, CanJIT () is false: %s", __FUNCTION__, GetID (), err.AsCString ());
+ }
DeallocateMemory (allocated_memory);
}
@@ -2930,13 +2668,14 @@ Process::DeallocateMemory (addr_t ptr)
ModuleSP
Process::ReadModuleFromMemory (const FileSpec& file_spec,
- lldb::addr_t header_addr)
+ lldb::addr_t header_addr,
+ size_t size_to_read)
{
ModuleSP module_sp (new Module (file_spec, ArchSpec()));
if (module_sp)
{
Error error;
- ObjectFile *objfile = module_sp->GetMemoryObjectFile (shared_from_this(), header_addr, error);
+ ObjectFile *objfile = module_sp->GetMemoryObjectFile (shared_from_this(), header_addr, error, size_to_read);
if (objfile)
return module_sp;
}
@@ -2989,6 +2728,7 @@ Process::Launch (ProcessLaunchInfo &launch_info)
Error error;
m_abi_sp.reset();
m_dyld_ap.reset();
+ m_jit_loaders_ap.reset();
m_system_runtime_ap.reset();
m_os_ap.reset();
m_process_input_reader.reset();
@@ -3065,6 +2805,8 @@ Process::Launch (ProcessLaunchInfo &launch_info)
if (dyld)
dyld->DidLaunch();
+ GetJITLoaders().DidLaunch();
+
SystemRuntime *system_runtime = GetSystemRuntime ();
if (system_runtime)
system_runtime->DidLaunch();
@@ -3111,6 +2853,8 @@ Process::LoadCore ()
DynamicLoader *dyld = GetDynamicLoader ();
if (dyld)
dyld->DidAttach();
+
+ GetJITLoaders().DidAttach();
SystemRuntime *system_runtime = GetSystemRuntime ();
if (system_runtime)
@@ -3134,6 +2878,23 @@ Process::GetDynamicLoader ()
return m_dyld_ap.get();
}
+const lldb::DataBufferSP
+Process::GetAuxvData()
+{
+ return DataBufferSP ();
+}
+
+JITLoaderList &
+Process::GetJITLoaders ()
+{
+ if (!m_jit_loaders_ap)
+ {
+ m_jit_loaders_ap.reset(new JITLoaderList());
+ JITLoader::LoadPlugins(this, *m_jit_loaders_ap);
+ }
+ return *m_jit_loaders_ap;
+}
+
SystemRuntime *
Process::GetSystemRuntime ()
{
@@ -3142,12 +2903,25 @@ Process::GetSystemRuntime ()
return m_system_runtime_ap.get();
}
+Process::AttachCompletionHandler::AttachCompletionHandler (Process *process, uint32_t exec_count) :
+ NextEventAction (process),
+ m_exec_count (exec_count)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("Process::AttachCompletionHandler::%s process=%p, exec_count=%" PRIu32, __FUNCTION__, static_cast<void*>(process), exec_count);
+}
Process::NextEventAction::EventActionResult
Process::AttachCompletionHandler::PerformAction (lldb::EventSP &event_sp)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
StateType state = ProcessEventData::GetStateFromEvent (event_sp.get());
- switch (state)
+ if (log)
+ log->Printf ("Process::AttachCompletionHandler::%s called with state %s (%d)", __FUNCTION__, StateAsCString(state), static_cast<int> (state));
+
+ switch (state)
{
case eStateRunning:
case eStateConnected:
@@ -3165,11 +2939,18 @@ Process::AttachCompletionHandler::PerformAction (lldb::EventSP &event_sp)
if (m_exec_count > 0)
{
--m_exec_count;
+
+ if (log)
+ log->Printf ("Process::AttachCompletionHandler::%s state %s: reduced remaining exec count to %" PRIu32 ", requesting resume", __FUNCTION__, StateAsCString(state), m_exec_count);
+
RequestResume();
return eEventActionRetry;
}
else
{
+ if (log)
+ log->Printf ("Process::AttachCompletionHandler::%s state %s: no more execs expected to start, continuing with attach", __FUNCTION__, StateAsCString(state));
+
m_process->CompleteAttach ();
return eEventActionSuccess;
}
@@ -3204,6 +2985,7 @@ Process::Attach (ProcessAttachInfo &attach_info)
m_abi_sp.reset();
m_process_input_reader.reset();
m_dyld_ap.reset();
+ m_jit_loaders_ap.reset();
m_system_runtime_ap.reset();
m_os_ap.reset();
@@ -3276,7 +3058,17 @@ Process::Attach (ProcessAttachInfo &attach_info)
{
match_info.GetProcessInfo().GetExecutableFile().GetPath (process_name, sizeof(process_name));
if (num_matches > 1)
- error.SetErrorStringWithFormat ("more than one process named %s", process_name);
+ {
+ StreamString s;
+ ProcessInstanceInfo::DumpTableHeader (s, platform_sp.get(), true, false);
+ for (size_t i = 0; i < num_matches; i++)
+ {
+ process_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(s, platform_sp.get(), true, false);
+ }
+ error.SetErrorStringWithFormat ("more than one process named %s:\n%s",
+ process_name,
+ s.GetData());
+ }
else
error.SetErrorStringWithFormat ("could not find a process named %s", process_name);
}
@@ -3340,9 +3132,26 @@ Process::Attach (ProcessAttachInfo &attach_info)
void
Process::CompleteAttach ()
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("Process::%s()", __FUNCTION__);
+
// Let the process subclass figure out at much as it can about the process
// before we go looking for a dynamic loader plug-in.
- DidAttach();
+ ArchSpec process_arch;
+ DidAttach(process_arch);
+
+ if (process_arch.IsValid())
+ {
+ m_target.SetArchitecture(process_arch);
+ if (log)
+ {
+ const char *triple_str = process_arch.GetTriple().getTriple().c_str ();
+ log->Printf ("Process::%s replacing process architecture with DidAttach() architecture: %s",
+ __FUNCTION__,
+ triple_str ? triple_str : "<null>");
+ }
+ }
// We just attached. If we have a platform, ask it for the process architecture, and if it isn't
// the same as the one we've already set, switch architectures.
@@ -3359,15 +3168,21 @@ Process::CompleteAttach ()
{
m_target.SetPlatform (platform_sp);
m_target.SetArchitecture(platform_arch);
+ if (log)
+ log->Printf ("Process::%s switching platform to %s and architecture to %s based on info from attach", __FUNCTION__, platform_sp->GetName().AsCString (""), platform_arch.GetTriple().getTriple().c_str ());
}
}
- else
+ else if (!process_arch.IsValid())
{
ProcessInstanceInfo process_info;
platform_sp->GetProcessInfo (GetID(), process_info);
const ArchSpec &process_arch = process_info.GetArchitecture();
if (process_arch.IsValid() && !m_target.GetArchitecture().IsExactMatch(process_arch))
+ {
m_target.SetArchitecture (process_arch);
+ if (log)
+ log->Printf ("Process::%s switching architecture to %s based on info the platform retrieved for pid %" PRIu64, __FUNCTION__, process_arch.GetTriple().getTriple().c_str (), GetID ());
+ }
}
}
@@ -3375,11 +3190,33 @@ Process::CompleteAttach ()
// plug-in
DynamicLoader *dyld = GetDynamicLoader ();
if (dyld)
+ {
dyld->DidAttach();
+ if (log)
+ {
+ ModuleSP exe_module_sp = m_target.GetExecutableModule ();
+ log->Printf ("Process::%s after DynamicLoader::DidAttach(), target executable is %s (using %s plugin)",
+ __FUNCTION__,
+ exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>",
+ dyld->GetPluginName().AsCString ("<unnamed>"));
+ }
+ }
+
+ GetJITLoaders().DidAttach();
SystemRuntime *system_runtime = GetSystemRuntime ();
if (system_runtime)
+ {
system_runtime->DidAttach();
+ if (log)
+ {
+ ModuleSP exe_module_sp = m_target.GetExecutableModule ();
+ log->Printf ("Process::%s after SystemRuntime::DidAttach(), target executable is %s (using %s plugin)",
+ __FUNCTION__,
+ exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>",
+ system_runtime->GetPluginName().AsCString("<unnamed>"));
+ }
+ }
m_os_ap.reset (OperatingSystem::FindPlugin (this, NULL));
// Figure out which one is the executable, and set that in our target:
@@ -3399,7 +3236,16 @@ Process::CompleteAttach ()
}
}
if (new_executable_module_sp)
+ {
m_target.SetExecutableModule (new_executable_module_sp, false);
+ if (log)
+ {
+ ModuleSP exe_module_sp = m_target.GetExecutableModule ();
+ log->Printf ("Process::%s after looping through modules, target executable is %s",
+ __FUNCTION__,
+ exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>");
+ }
+ }
}
Error
@@ -3520,6 +3366,7 @@ Process::Halt (bool clear_thread_plans)
EventSP event_sp;
Error error (WillHalt());
+ bool restored_process_events = false;
if (error.Success())
{
@@ -3531,6 +3378,10 @@ Process::Halt (bool clear_thread_plans)
{
if (m_public_state.GetValue() == eStateAttaching)
{
+ // Don't hijack and eat the eStateExited as the code that was doing
+ // the attach will be waiting for this event...
+ RestorePrivateProcessEvents();
+ restored_process_events = true;
SetExitStatus(SIGKILL, "Cancelled async attach.");
Destroy ();
}
@@ -3547,7 +3398,7 @@ Process::Halt (bool clear_thread_plans)
// Wait for 1 second for the process to stop.
TimeValue timeout_time;
timeout_time = TimeValue::Now();
- timeout_time.OffsetWithSeconds(1);
+ timeout_time.OffsetWithSeconds(10);
bool got_event = halt_listener.WaitForEvent (&timeout_time, event_sp);
StateType state = ProcessEventData::GetStateFromEvent(event_sp.get());
@@ -3579,7 +3430,8 @@ Process::Halt (bool clear_thread_plans)
}
}
// Resume our private state thread before we post the event (if any)
- RestorePrivateProcessEvents();
+ if (!restored_process_events)
+ RestorePrivateProcessEvents();
// Post any event we might have consumed. If all goes well, we will have
// stopped the process, intercepted the event and set the interrupted
@@ -3671,6 +3523,9 @@ Process::Detach (bool keep_stopped)
}
}
+ m_thread_list.DiscardThreadPlans();
+ DisableAllBreakpointSites();
+
error = DoDetach(keep_stopped);
if (error.Success())
{
@@ -3738,9 +3593,14 @@ Process::Destroy ()
}
m_stdio_communication.StopReadThread();
m_stdio_communication.Disconnect();
+
if (m_process_input_reader)
+ {
+ m_process_input_reader->SetIsDone(true);
+ m_process_input_reader->Cancel();
m_process_input_reader.reset();
-
+ }
+
// If we exited when we were waiting for a process to stop, then
// forward the event here so we don't lose the event
if (exit_event_sp)
@@ -3831,7 +3691,7 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
break;
default:
// TODO: make this work correctly. For now always report
- // run if we aren't running so we don't miss any runnning
+ // run if we aren't running so we don't miss any running
// events. If I run the lldb/test/thread/a.out file and
// break at main.cpp:58, run and hit the breakpoints on
// multiple threads, then somehow during the stepping over
@@ -3866,32 +3726,33 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
{
if (log)
log->Printf ("Process::ShouldBroadcastEvent (%p) stopped due to an interrupt, state: %s",
- event_ptr,
+ static_cast<void*>(event_ptr),
StateAsCString(state));
+ // Even though we know we are going to stop, we should let the threads have a look at the stop,
+ // so they can properly set their state.
+ m_thread_list.ShouldStop (event_ptr);
return_value = true;
}
else
{
bool was_restarted = ProcessEventData::GetRestartedFromEvent (event_ptr);
bool should_resume = false;
-
+
// It makes no sense to ask "ShouldStop" if we've already been restarted...
// Asking the thread list is also not likely to go well, since we are running again.
// So in that case just report the event.
-
+
if (!was_restarted)
should_resume = m_thread_list.ShouldStop (event_ptr) == false;
-
+
if (was_restarted || should_resume || m_resume_requested)
{
Vote stop_vote = m_thread_list.ShouldReportStop (event_ptr);
if (log)
log->Printf ("Process::ShouldBroadcastEvent: should_stop: %i state: %s was_restarted: %i stop_vote: %d.",
- should_resume,
- StateAsCString(state),
- was_restarted,
- stop_vote);
-
+ should_resume, StateAsCString(state),
+ was_restarted, stop_vote);
+
switch (stop_vote)
{
case eVoteYes:
@@ -3902,15 +3763,17 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
return_value = false;
break;
}
-
+
if (!was_restarted)
{
if (log)
- log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process from state: %s", event_ptr, StateAsCString(state));
+ log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process from state: %s",
+ static_cast<void*>(event_ptr),
+ StateAsCString(state));
ProcessEventData::SetRestartedInEvent(event_ptr, true);
PrivateResume ();
}
-
+
}
else
{
@@ -3921,7 +3784,7 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
}
break;
}
-
+
// Forcing the next event delivery is a one shot deal. So reset it here.
m_force_next_event_delivery = false;
@@ -3931,14 +3794,13 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
// because the PublicState reflects the last event pulled off the queue, and there may be several
// events stacked up on the queue unserviced. So the PublicState may not reflect the last broadcasted event
// yet. m_last_broadcast_state gets updated here.
-
+
if (return_value)
m_last_broadcast_state = state;
-
+
if (log)
log->Printf ("Process::ShouldBroadcastEvent (%p) => new state: %s, last broadcast state: %s - %s",
- event_ptr,
- StateAsCString(state),
+ static_cast<void*>(event_ptr), StateAsCString(state),
StateAsCString(m_last_broadcast_state),
return_value ? "YES" : "NO");
return return_value;
@@ -3960,11 +3822,23 @@ Process::StartPrivateStateThread (bool force)
// Create a thread that watches our internal state and controls which
// events make it to clients (into the DCProcess event queue).
char thread_name[1024];
- if (already_running)
- snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state-override(pid=%" PRIu64 ")>", GetID());
+
+ if (Host::MAX_THREAD_NAME_LENGTH <= 16)
+ {
+ // On platforms with abbreviated thread name lengths, choose thread names that fit within the limit.
+ if (already_running)
+ snprintf(thread_name, sizeof(thread_name), "intern-state-OV");
+ else
+ snprintf(thread_name, sizeof(thread_name), "intern-state");
+ }
else
- snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state(pid=%" PRIu64 ")>", GetID());
-
+ {
+ if (already_running)
+ snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state-override(pid=%" PRIu64 ")>", GetID());
+ else
+ snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state(pid=%" PRIu64 ")>", GetID());
+ }
+
// Create the private state thread, and start it running.
m_private_state_thread = Host::ThreadCreate (thread_name, Process::PrivateStateThread, this, NULL);
bool success = IS_VALID_LLDB_HOST_THREAD(m_private_state_thread);
@@ -4116,6 +3990,7 @@ Process::HandlePrivateEvent (EventSP &event_sp)
if (should_broadcast)
{
+ const bool is_hijacked = IsHijackedForEvent(eBroadcastBitStateChanged);
if (log)
{
log->Printf ("Process::%s (pid = %" PRIu64 ") broadcasting new state %s (old state %s) to %s",
@@ -4123,7 +3998,7 @@ Process::HandlePrivateEvent (EventSP &event_sp)
GetID(),
StateAsCString(new_state),
StateAsCString (GetState ()),
- IsHijackedForEvent(eBroadcastBitStateChanged) ? "hijacked" : "public");
+ is_hijacked ? "hijacked" : "public");
}
Process::ProcessEventData::SetUpdateStateOnRemoval(event_sp.get());
if (StateIsRunningState (new_state))
@@ -4132,9 +4007,46 @@ Process::HandlePrivateEvent (EventSP &event_sp)
// as this means the curses GUI is in use...
if (!GetTarget().GetDebugger().IsForwardingEvents())
PushProcessIOHandler ();
+ m_iohandler_sync.SetValue(true, eBroadcastAlways);
+ }
+ else if (StateIsStoppedState(new_state, false))
+ {
+ m_iohandler_sync.SetValue(false, eBroadcastNever);
+ if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
+ {
+ // If the lldb_private::Debugger is handling the events, we don't
+ // want to pop the process IOHandler here, we want to do it when
+ // we receive the stopped event so we can carefully control when
+ // the process IOHandler is popped because when we stop we want to
+ // display some text stating how and why we stopped, then maybe some
+ // process/thread/frame info, and then we want the "(lldb) " prompt
+ // to show up. If we pop the process IOHandler here, then we will
+ // cause the command interpreter to become the top IOHandler after
+ // the process pops off and it will update its prompt right away...
+ // See the Debugger.cpp file where it calls the function as
+ // "process_sp->PopProcessIOHandler()" to see where I am talking about.
+ // Otherwise we end up getting overlapping "(lldb) " prompts and
+ // garbled output.
+ //
+ // If we aren't handling the events in the debugger (which is indicated
+ // by "m_target.GetDebugger().IsHandlingEvents()" returning false) or we
+ // are hijacked, then we always pop the process IO handler manually.
+ // Hijacking happens when the internal process state thread is running
+ // thread plans, or when commands want to run in synchronous mode
+ // and they call "process->WaitForProcessToStop()". An example of something
+ // that will hijack the events is a simple expression:
+ //
+ // (lldb) expr (int)puts("hello")
+ //
+ // This will cause the internal process state thread to resume and halt
+ // the process (and _it_ will hijack the eBroadcastBitStateChanged
+ // events) and we do need the IO handler to be pushed and popped
+ // correctly.
+
+ if (is_hijacked || m_target.GetDebugger().IsHandlingEvents() == false)
+ PopProcessIOHandler ();
+ }
}
- else if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
- PopProcessIOHandler ();
BroadcastEvent (event_sp);
}
@@ -4168,7 +4080,8 @@ Process::RunPrivateStateThread ()
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread starting...", __FUNCTION__, this, GetID());
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread starting...",
+ __FUNCTION__, static_cast<void*>(this), GetID());
bool exit_now = false;
while (!exit_now)
@@ -4178,13 +4091,15 @@ Process::RunPrivateStateThread ()
if (event_sp->BroadcasterIs(&m_private_state_control_broadcaster))
{
if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") got a control event: %d", __FUNCTION__, this, GetID(), event_sp->GetType());
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") got a control event: %d",
+ __FUNCTION__, static_cast<void*>(this), GetID(),
+ event_sp->GetType());
switch (event_sp->GetType())
{
case eBroadcastInternalStateControlStop:
exit_now = true;
- break; // doing any internal state managment below
+ break; // doing any internal state management below
case eBroadcastInternalStateControlPause:
control_only = true;
@@ -4194,7 +4109,7 @@ Process::RunPrivateStateThread ()
control_only = false;
break;
}
-
+
m_private_state_control_wait.SetValue (true, eBroadcastAlways);
continue;
}
@@ -4203,13 +4118,17 @@ Process::RunPrivateStateThread ()
if (m_public_state.GetValue() == eStateAttaching)
{
if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt while attaching - forwarding interrupt.", __FUNCTION__, this, GetID());
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt while attaching - forwarding interrupt.",
+ __FUNCTION__, static_cast<void*>(this),
+ GetID());
BroadcastEvent (eBroadcastBitInterrupt, NULL);
}
else
{
if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt - Halting.", __FUNCTION__, this, GetID());
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt - Halting.",
+ __FUNCTION__, static_cast<void*>(this),
+ GetID());
Halt();
}
continue;
@@ -4233,7 +4152,9 @@ Process::RunPrivateStateThread ()
internal_state == eStateDetached )
{
if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") about to exit with internal state %s...", __FUNCTION__, this, GetID(), StateAsCString(internal_state));
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") about to exit with internal state %s...",
+ __FUNCTION__, static_cast<void*>(this), GetID(),
+ StateAsCString(internal_state));
break;
}
@@ -4241,7 +4162,8 @@ Process::RunPrivateStateThread ()
// Verify log is still enabled before attempting to write to it...
if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", __FUNCTION__, this, GetID());
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread exiting...",
+ __FUNCTION__, static_cast<void*>(this), GetID());
m_public_run_lock.SetStopped();
m_private_state_control_wait.SetValue (true, eBroadcastAlways);
@@ -4303,8 +4225,14 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
return;
m_process_sp->SetPublicState (m_state, Process::ProcessEventData::GetRestartedFromEvent(event_ptr));
-
- // If we're stopped and haven't restarted, then do the breakpoint commands here:
+
+ // If this is a halt event, even if the halt stopped with some reason other than a plain interrupt (e.g. we had
+ // already stopped for a breakpoint when the halt request came through) don't do the StopInfo actions, as they may
+ // end up restarting the process.
+ if (m_interrupted)
+ return;
+
+ // If we're stopped and haven't restarted, then do the StopInfo actions here:
if (m_state == eStateStopped && ! m_restarted)
{
ThreadList &curr_thread_list = m_process_sp->GetThreadList();
@@ -4418,7 +4346,8 @@ void
Process::ProcessEventData::Dump (Stream *s) const
{
if (m_process_sp)
- s->Printf(" process = %p (pid = %" PRIu64 "), ", m_process_sp.get(), m_process_sp->GetID());
+ s->Printf(" process = %p (pid = %" PRIu64 "), ",
+ static_cast<void*>(m_process_sp.get()), m_process_sp->GetID());
s->Printf("state = %s", StateAsCString(GetState()));
}
@@ -4601,7 +4530,9 @@ Process::GetAsyncProfileData (char *buf, size_t buf_size, Error &error)
{
Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::GetProfileData (buf = %p, size = %" PRIu64 ")", buf, (uint64_t)buf_size);
+ log->Printf ("Process::GetProfileData (buf = %p, size = %" PRIu64 ")",
+ static_cast<void*>(buf),
+ static_cast<uint64_t>(buf_size));
if (bytes_available > buf_size)
{
memcpy(buf, one_profile_data.c_str(), buf_size);
@@ -4631,7 +4562,9 @@ Process::GetSTDOUT (char *buf, size_t buf_size, Error &error)
{
Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::GetSTDOUT (buf = %p, size = %" PRIu64 ")", buf, (uint64_t)buf_size);
+ log->Printf ("Process::GetSTDOUT (buf = %p, size = %" PRIu64 ")",
+ static_cast<void*>(buf),
+ static_cast<uint64_t>(buf_size));
if (bytes_available > buf_size)
{
memcpy(buf, m_stdout_data.c_str(), buf_size);
@@ -4657,7 +4590,9 @@ Process::GetSTDERR (char *buf, size_t buf_size, Error &error)
{
Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::GetSTDERR (buf = %p, size = %" PRIu64 ")", buf, (uint64_t)buf_size);
+ log->Printf ("Process::GetSTDERR (buf = %p, size = %" PRIu64 ")",
+ static_cast<void*>(buf),
+ static_cast<uint64_t>(buf_size));
if (bytes_available > buf_size)
{
memcpy(buf, m_stderr_data.c_str(), buf_size);
@@ -4680,13 +4615,6 @@ Process::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_
process->AppendSTDOUT (static_cast<const char *>(src), src_len);
}
-void
-Process::ResetProcessIOHandler ()
-{
- m_process_input_reader.reset();
-}
-
-
class IOHandlerProcessSTDIO :
public IOHandler
{
@@ -4697,8 +4625,7 @@ public:
m_process (process),
m_read_file (),
m_write_file (write_fd, false),
- m_pipe_read(),
- m_pipe_write()
+ m_pipe ()
{
m_read_file.SetDescriptor(GetInputFD(), false);
}
@@ -4712,30 +4639,15 @@ public:
bool
OpenPipes ()
{
- if (m_pipe_read.IsValid() && m_pipe_write.IsValid())
+ if (m_pipe.IsValid())
return true;
-
- int fds[2];
-#ifdef _MSC_VER
- // pipe is not supported on windows so default to a fail condition
- int err = 1;
-#else
- int err = pipe(fds);
-#endif
- if (err == 0)
- {
- m_pipe_read.SetDescriptor(fds[0], true);
- m_pipe_write.SetDescriptor(fds[1], true);
- return true;
- }
- return false;
+ return m_pipe.Open();
}
void
ClosePipes()
{
- m_pipe_read.Close();
- m_pipe_write.Close();
+ m_pipe.Close();
}
// Each IOHandler gets to run until it is done. It should read data
@@ -4750,14 +4662,14 @@ public:
if (OpenPipes())
{
const int read_fd = m_read_file.GetDescriptor();
- const int pipe_read_fd = m_pipe_read.GetDescriptor();
+ const int pipe_read_fd = m_pipe.GetReadFileDescriptor();
TerminalState terminal_state;
terminal_state.Save (read_fd, false);
Terminal terminal(read_fd);
terminal.SetCanonical(false);
terminal.SetEcho(false);
// FD_ZERO, FD_SET are not supported on windows
-#ifndef _MSC_VER
+#ifndef _WIN32
while (!GetIsDone())
{
fd_set read_fdset;
@@ -4791,9 +4703,19 @@ public:
if (FD_ISSET (pipe_read_fd, &read_fdset))
{
// Consume the interrupt byte
- n = 1;
- m_pipe_read.Read (&ch, n);
- SetIsDone(true);
+ if (m_pipe.Read (&ch, 1) == 1)
+ {
+ switch (ch)
+ {
+ case 'q':
+ SetIsDone(true);
+ break;
+ case 'i':
+ if (StateIsRunningState(m_process->GetState()))
+ m_process->Halt();
+ break;
+ }
+ }
}
}
}
@@ -4828,16 +4750,40 @@ public:
virtual void
Cancel ()
{
- size_t n = 1;
- char ch = 'q';
- m_pipe_write.Write (&ch, n);
+ char ch = 'q'; // Send 'q' for quit
+ m_pipe.Write (&ch, 1);
}
- virtual void
+ virtual bool
Interrupt ()
{
- if (StateIsRunningState(m_process->GetState()))
- m_process->SendAsyncInterrupt();
+ // Do only things that are safe to do in an interrupt context (like in
+ // a SIGINT handler), like write 1 byte to a file descriptor. This will
+ // interrupt the IOHandlerProcessSTDIO::Run() and we can look at the byte
+ // that was written to the pipe and then call m_process->Halt() from a
+ // much safer location in code.
+ if (m_active)
+ {
+ char ch = 'i'; // Send 'i' for interrupt
+ return m_pipe.Write (&ch, 1) == 1;
+ }
+ else
+ {
+ // This IOHandler might be pushed on the stack, but not being run currently
+ // so do the right thing if we aren't actively watching for STDIN by sending
+ // the interrupt to the process. Otherwise the write to the pipe above would
+ // do nothing. This can happen when the command interpreter is running and
+ // gets a "expression ...". It will be on the IOHandler thread and sending
+ // the input is complete to the delegate which will cause the expression to
+ // run, which will push the process IO handler, but not run it.
+
+ if (StateIsRunningState(m_process->GetState()))
+ {
+ m_process->SendAsyncInterrupt();
+ return true;
+ }
+ }
+ return false;
}
virtual void
@@ -4850,28 +4796,10 @@ protected:
Process *m_process;
File m_read_file; // Read from this file (usually actual STDIN for LLDB
File m_write_file; // Write to this file (usually the master pty for getting io to debuggee)
- File m_pipe_read;
- File m_pipe_write;
-
+ Pipe m_pipe;
};
void
-Process::WatchForSTDIN (IOHandler &io_handler)
-{
-}
-
-void
-Process::CancelWatchForSTDIN (bool exited)
-{
- if (m_process_input_reader)
- {
- if (exited)
- m_process_input_reader->SetIsDone(true);
- m_process_input_reader->Cancel();
- }
-}
-
-void
Process::SetSTDIOFileDescriptor (int fd)
{
// First set up the Read Thread for reading/handling process I/O
@@ -4894,7 +4822,15 @@ Process::SetSTDIOFileDescriptor (int fd)
}
}
-void
+bool
+Process::ProcessIOHandlerIsActive ()
+{
+ IOHandlerSP io_handler_sp (m_process_input_reader);
+ if (io_handler_sp)
+ return m_target.GetDebugger().IsTopIOHandler (io_handler_sp);
+ return false;
+}
+bool
Process::PushProcessIOHandler ()
{
IOHandlerSP io_handler_sp (m_process_input_reader);
@@ -4902,18 +4838,18 @@ Process::PushProcessIOHandler ()
{
io_handler_sp->SetIsDone(false);
m_target.GetDebugger().PushIOHandler (io_handler_sp);
+ return true;
}
+ return false;
}
-void
+bool
Process::PopProcessIOHandler ()
{
IOHandlerSP io_handler_sp (m_process_input_reader);
if (io_handler_sp)
- {
- io_handler_sp->Cancel();
- m_target.GetDebugger().PopIOHandler (io_handler_sp);
- }
+ return m_target.GetDebugger().PopIOHandler (io_handler_sp);
+ return false;
}
// The process needs to know about installed plug-ins
@@ -4929,52 +4865,52 @@ Process::SettingsTerminate ()
Thread::SettingsTerminate ();
}
-ExecutionResults
+ExpressionResults
Process::RunThreadPlan (ExecutionContext &exe_ctx,
lldb::ThreadPlanSP &thread_plan_sp,
const EvaluateExpressionOptions &options,
Stream &errors)
{
- ExecutionResults return_value = eExecutionSetupError;
-
+ ExpressionResults return_value = eExpressionSetupError;
+
if (thread_plan_sp.get() == NULL)
{
errors.Printf("RunThreadPlan called with empty thread plan.");
- return eExecutionSetupError;
+ return eExpressionSetupError;
}
-
+
if (!thread_plan_sp->ValidatePlan(NULL))
{
errors.Printf ("RunThreadPlan called with an invalid thread plan.");
- return eExecutionSetupError;
+ return eExpressionSetupError;
}
-
+
if (exe_ctx.GetProcessPtr() != this)
{
errors.Printf("RunThreadPlan called on wrong process.");
- return eExecutionSetupError;
+ return eExpressionSetupError;
}
Thread *thread = exe_ctx.GetThreadPtr();
if (thread == NULL)
{
errors.Printf("RunThreadPlan called with invalid thread.");
- return eExecutionSetupError;
+ return eExpressionSetupError;
}
-
+
// We rely on the thread plan we are running returning "PlanCompleted" if when it successfully completes.
// For that to be true the plan can't be private - since private plans suppress themselves in the
// GetCompletedPlan call.
-
+
bool orig_plan_private = thread_plan_sp->GetPrivate();
thread_plan_sp->SetPrivate(false);
-
+
if (m_private_state.GetValue() != eStateStopped)
{
errors.Printf ("RunThreadPlan called while the private state was not stopped.");
- return eExecutionSetupError;
+ return eExpressionSetupError;
}
-
+
// Save the thread & frame from the exe_ctx for restoration after we run
const uint32_t thread_idx_id = thread->GetIndexID();
StackFrameSP selected_frame_sp = thread->GetSelectedFrame();
@@ -4985,17 +4921,17 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
if (!selected_frame_sp)
{
errors.Printf("RunThreadPlan called without a selected frame on thread %d", thread_idx_id);
- return eExecutionSetupError;
+ return eExpressionSetupError;
}
}
-
+
StackID ctx_frame_id = selected_frame_sp->GetStackID();
// N.B. Running the target may unset the currently selected thread and frame. We don't want to do that either,
// so we should arrange to reset them as well.
-
+
lldb::ThreadSP selected_thread_sp = GetThreadList().GetSelectedThread();
-
+
uint32_t selected_tid;
StackID selected_stack_id;
if (selected_thread_sp)
@@ -5021,7 +4957,6 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// we are fielding public events here.
if (log)
log->Printf ("Running thread plan on private state thread, spinning up another state thread to handle the events.");
-
backup_private_state_thread = m_private_state_thread;
@@ -5036,13 +4971,13 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// Have to make sure our public state is stopped, since otherwise the reporting logic below doesn't work correctly.
old_state = m_public_state.GetValue();
m_public_state.SetValueNoLock(eStateStopped);
-
+
// Now spin up the private state thread:
StartPrivateStateThread(true);
}
-
+
thread->QueueThreadPlan(thread_plan_sp, false); // This used to pass "true" does that make sense?
-
+
if (options.GetDebug())
{
// In this case, we aren't actually going to run, we just want to stop right away.
@@ -5051,22 +4986,22 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// is only cosmetic, and this functionality is only of use to lldb developers who can
// live with not pretty...
thread->Flush();
- return eExecutionStoppedForDebug;
+ return eExpressionStoppedForDebug;
}
-
+
Listener listener("lldb.process.listener.run-thread-plan");
-
+
lldb::EventSP event_to_broadcast_sp;
-
+
{
// This process event hijacker Hijacks the Public events and its destructor makes sure that the process events get
// restored on exit to the function.
//
// If the event needs to propagate beyond the hijacker (e.g., the process exits during execution), then the event
// is put into event_to_broadcast_sp for rebroadcasting.
-
+
ProcessEventHijacker run_thread_plan_hijacker (*this, &listener);
-
+
if (log)
{
StreamString s;
@@ -5076,66 +5011,114 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
thread->GetID(),
s.GetData());
}
-
+
bool got_event;
lldb::EventSP event_sp;
lldb::StateType stop_state = lldb::eStateInvalid;
-
+
TimeValue* timeout_ptr = NULL;
TimeValue real_timeout;
-
+
bool before_first_timeout = true; // This is set to false the first time that we have to halt the target.
bool do_resume = true;
bool handle_running_event = true;
const uint64_t default_one_thread_timeout_usec = 250000;
-
+
// This is just for accounting:
uint32_t num_resumes = 0;
+
+ uint32_t timeout_usec = options.GetTimeoutUsec();
+ uint32_t one_thread_timeout_usec;
+ uint32_t all_threads_timeout_usec = 0;
- TimeValue one_thread_timeout = TimeValue::Now();
- TimeValue final_timeout = one_thread_timeout;
+ // If we are going to run all threads the whole time, or if we are only going to run one thread,
+ // then we don't need the first timeout. So we set the final timeout, and pretend we are after the
+ // first timeout already.
- uint32_t timeout_usec = options.GetTimeoutUsec();
- if (options.GetTryAllThreads())
+ if (!options.GetStopOthers() || !options.GetTryAllThreads())
{
- // If we are running all threads then we take half the time to run all threads, bounded by
- // .25 sec.
- if (options.GetTimeoutUsec() == 0)
- one_thread_timeout.OffsetWithMicroSeconds(default_one_thread_timeout_usec);
- else
- {
- uint64_t computed_timeout = timeout_usec / 2;
- if (computed_timeout > default_one_thread_timeout_usec)
- computed_timeout = default_one_thread_timeout_usec;
- one_thread_timeout.OffsetWithMicroSeconds(computed_timeout);
- }
- final_timeout.OffsetWithMicroSeconds (timeout_usec);
+ before_first_timeout = false;
+ one_thread_timeout_usec = 0;
+ all_threads_timeout_usec = timeout_usec;
}
else
{
- if (timeout_usec != 0)
- final_timeout.OffsetWithMicroSeconds(timeout_usec);
+ uint32_t option_one_thread_timeout = options.GetOneThreadTimeoutUsec();
+
+ // If the overall wait is forever, then we only need to set the one thread timeout:
+ if (timeout_usec == 0)
+ {
+ if (option_one_thread_timeout != 0)
+ one_thread_timeout_usec = option_one_thread_timeout;
+ else
+ one_thread_timeout_usec = default_one_thread_timeout_usec;
+ }
+ else
+ {
+ // Otherwise, if the one thread timeout is set, make sure it isn't longer than the overall timeout,
+ // and use it, otherwise use half the total timeout, bounded by the default_one_thread_timeout_usec.
+ uint64_t computed_one_thread_timeout;
+ if (option_one_thread_timeout != 0)
+ {
+ if (timeout_usec < option_one_thread_timeout)
+ {
+ errors.Printf("RunThreadPlan called without one thread timeout greater than total timeout");
+ return eExpressionSetupError;
+ }
+ computed_one_thread_timeout = option_one_thread_timeout;
+ }
+ else
+ {
+ computed_one_thread_timeout = timeout_usec / 2;
+ if (computed_one_thread_timeout > default_one_thread_timeout_usec)
+ computed_one_thread_timeout = default_one_thread_timeout_usec;
+ }
+ one_thread_timeout_usec = computed_one_thread_timeout;
+ all_threads_timeout_usec = timeout_usec - one_thread_timeout_usec;
+
+ }
}
+
+ if (log)
+ log->Printf ("Stop others: %u, try all: %u, before_first: %u, one thread: %" PRIu32 " - all threads: %" PRIu32 ".\n",
+ options.GetStopOthers(),
+ options.GetTryAllThreads(),
+ before_first_timeout,
+ one_thread_timeout_usec,
+ all_threads_timeout_usec);
// This isn't going to work if there are unfetched events on the queue.
// Are there cases where we might want to run the remaining events here, and then try to
// call the function? That's probably being too tricky for our own good.
-
+
Event *other_events = listener.PeekAtNextEvent();
if (other_events != NULL)
{
errors.Printf("Calling RunThreadPlan with pending events on the queue.");
- return eExecutionSetupError;
+ return eExpressionSetupError;
}
-
+
// We also need to make sure that the next event is delivered. We might be calling a function as part of
// a thread plan, in which case the last delivered event could be the running event, and we don't want
// event coalescing to cause us to lose OUR running event...
ForceNextEventDelivery();
-
+
// This while loop must exit out the bottom, there's cleanup that we need to do when we are done.
// So don't call return anywhere within it.
+#ifdef LLDB_RUN_THREAD_HALT_WITH_EVENT
+ // It's pretty much impossible to write test cases for things like:
+ // One thread timeout expires, I go to halt, but the process already stopped
+ // on the function call stop breakpoint. Turning on this define will make us not
+ // fetch the first event till after the halt. So if you run a quick function, it will have
+ // completed, and the completion event will be waiting, when you interrupt for halt.
+ // The expression evaluation should still succeed.
+ bool miss_first_event = true;
+#endif
+ TimeValue one_thread_timeout;
+ TimeValue final_timeout;
+
+
while (1)
{
// We usually want to resume the process if we get to the top of the loop.
@@ -5146,11 +5129,11 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
do_resume,
handle_running_event,
before_first_timeout);
-
+
if (do_resume || handle_running_event)
{
// Do the initial resume and wait for the running event before going further.
-
+
if (do_resume)
{
num_resumes++;
@@ -5160,14 +5143,14 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
errors.Printf("Error resuming inferior the %d time: \"%s\".\n",
num_resumes,
resume_error.AsCString());
- return_value = eExecutionSetupError;
+ return_value = eExpressionSetupError;
break;
}
}
-
+
TimeValue resume_timeout = TimeValue::Now();
resume_timeout.OffsetWithMicroSeconds(500000);
-
+
got_event = listener.WaitForEvent(&resume_timeout, event_sp);
if (!got_event)
{
@@ -5176,16 +5159,16 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
num_resumes);
errors.Printf("Didn't get any event after resume %d, exiting.", num_resumes);
- return_value = eExecutionSetupError;
+ return_value = eExpressionSetupError;
break;
}
-
+
stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
if (stop_state != eStateRunning)
{
bool restarted = false;
-
+
if (stop_state == eStateStopped)
{
restarted = Process::ProcessEventData::GetRestartedFromEvent(event_sp.get());
@@ -5198,20 +5181,20 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
do_resume,
handle_running_event);
}
-
+
if (restarted)
{
// This is probably an overabundance of caution, I don't think I should ever get a stopped & restarted
// event here. But if I do, the best thing is to Halt and then get out of here.
Halt();
}
-
+
errors.Printf("Didn't get running event after initial resume, got %s instead.",
StateAsCString(stop_state));
- return_value = eExecutionSetupError;
+ return_value = eExpressionSetupError;
break;
}
-
+
if (log)
log->PutCString ("Process::RunThreadPlan(): resuming succeeded.");
// We need to call the function synchronously, so spin waiting for it to return.
@@ -5225,17 +5208,25 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
if (log)
log->PutCString ("Process::RunThreadPlan(): waiting for next event.");
}
-
+
if (before_first_timeout)
{
if (options.GetTryAllThreads())
+ {
+ one_thread_timeout = TimeValue::Now();
+ one_thread_timeout.OffsetWithMicroSeconds(one_thread_timeout_usec);
timeout_ptr = &one_thread_timeout;
+ }
else
{
if (timeout_usec == 0)
timeout_ptr = NULL;
else
+ {
+ final_timeout = TimeValue::Now();
+ final_timeout.OffsetWithMicroSeconds (timeout_usec);
timeout_ptr = &final_timeout;
+ }
}
}
else
@@ -5243,12 +5234,16 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
if (timeout_usec == 0)
timeout_ptr = NULL;
else
+ {
+ final_timeout = TimeValue::Now();
+ final_timeout.OffsetWithMicroSeconds (all_threads_timeout_usec);
timeout_ptr = &final_timeout;
+ }
}
-
+
do_resume = true;
handle_running_event = true;
-
+
// Now wait for the process to stop again:
event_sp.reset();
@@ -5266,8 +5261,18 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
}
}
+#ifdef LLDB_RUN_THREAD_HALT_WITH_EVENT
+ // See comment above...
+ if (miss_first_event)
+ {
+ usleep(1000);
+ miss_first_event = false;
+ got_event = false;
+ }
+ else
+#endif
got_event = listener.WaitForEvent (timeout_ptr, event_sp);
-
+
if (got_event)
{
if (event_sp.get())
@@ -5276,7 +5281,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
if (event_sp->GetType() == eBroadcastBitInterrupt)
{
Halt();
- return_value = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
errors.Printf ("Execution halted by user interrupt.");
if (log)
log->Printf ("Process::RunThreadPlan(): Got interrupted by eBroadcastBitInterrupted, exiting.");
@@ -5287,7 +5292,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
if (log)
log->Printf("Process::RunThreadPlan(): in while loop, got event: %s.", StateAsCString(stop_state));
-
+
switch (stop_state)
{
case lldb::eStateStopped:
@@ -5299,7 +5304,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// Ooh, our thread has vanished. Unlikely that this was successful execution...
if (log)
log->Printf ("Process::RunThreadPlan(): execution completed but our thread (index-id=%u) has vanished.", thread_idx_id);
- return_value = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
}
else
{
@@ -5313,17 +5318,15 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
keep_going = true;
do_resume = false;
handle_running_event = true;
-
+
}
else
{
-
StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());
StopReason stop_reason = eStopReasonInvalid;
if (stop_info_sp)
stop_reason = stop_info_sp->GetStopReason();
-
-
+
// FIXME: We only check if the stop reason is plan complete, should we make sure that
// it is OUR plan that is complete?
if (stop_reason == eStopReasonPlanComplete)
@@ -5334,7 +5337,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// after this point.
if (thread_plan_sp)
thread_plan_sp->SetPrivate (orig_plan_private);
- return_value = eExecutionCompleted;
+ return_value = eExpressionCompleted;
}
else
{
@@ -5343,7 +5346,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
if (log)
log->Printf ("Process::RunThreadPlan() stopped for breakpoint: %s.", stop_info_sp->GetDescription());
- return_value = eExecutionHitBreakpoint;
+ return_value = eExpressionHitBreakpoint;
if (!options.DoesIgnoreBreakpoints())
{
event_to_broadcast_sp = event_sp;
@@ -5355,7 +5358,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete.");
if (!options.DoesUnwindOnError())
event_to_broadcast_sp = event_sp;
- return_value = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
}
}
}
@@ -5374,16 +5377,16 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
default:
if (log)
log->Printf("Process::RunThreadPlan(): execution stopped with unexpected state: %s.", StateAsCString(stop_state));
-
+
if (stop_state == eStateExited)
event_to_broadcast_sp = event_sp;
-
+
errors.Printf ("Execution stopped with unexpected state.\n");
- return_value = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
break;
}
}
-
+
if (keep_going)
continue;
else
@@ -5393,7 +5396,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
if (log)
log->PutCString ("Process::RunThreadPlan(): got_event was true, but the event pointer was null. How odd...");
- return_value = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
break;
}
}
@@ -5402,15 +5405,24 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// If we didn't get an event that means we've timed out...
// We will interrupt the process here. Depending on what we were asked to do we will
// either exit, or try with all threads running for the same timeout.
-
+
if (log) {
if (options.GetTryAllThreads())
{
- uint64_t remaining_time = final_timeout - TimeValue::Now();
if (before_first_timeout)
- log->Printf ("Process::RunThreadPlan(): Running function with one thread timeout timed out, "
- "running till for %" PRIu64 " usec with all threads enabled.",
- remaining_time);
+ {
+ if (timeout_usec != 0)
+ {
+ log->Printf ("Process::RunThreadPlan(): Running function with one thread timeout timed out, "
+ "running for %" PRIu32 " usec with all threads enabled.",
+ all_threads_timeout_usec);
+ }
+ else
+ {
+ log->Printf ("Process::RunThreadPlan(): Running function with one thread timeout timed out, "
+ "running forever with all threads enabled.");
+ }
+ }
else
log->Printf ("Process::RunThreadPlan(): Restarting function with all threads enabled "
"and timeout: %u timed out, abandoning execution.",
@@ -5421,13 +5433,13 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
"abandoning execution.",
timeout_usec);
}
-
+
// It is possible that between the time we issued the Halt, and we get around to calling Halt the target
// could have stopped. That's fine, Halt will figure that out and send the appropriate Stopped event.
// BUT it is also possible that we stopped & restarted (e.g. hit a signal with "stop" set to false.) In
// that case, we'll get the stopped & restarted event, and we should go back to waiting for the Halt's
// stopped event. That's what this while loop does.
-
+
bool back_to_top = true;
uint32_t try_halt_again = 0;
bool do_halt = true;
@@ -5445,12 +5457,12 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
if (log)
log->PutCString ("Process::RunThreadPlan(): Halt succeeded.");
-
+
real_timeout = TimeValue::Now();
real_timeout.OffsetWithMicroSeconds(500000);
got_event = listener.WaitForEvent(&real_timeout, event_sp);
-
+
if (got_event)
{
stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
@@ -5461,22 +5473,22 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
&& Process::ProcessEventData::GetInterruptedFromEvent(event_sp.get()))
log->PutCString (" Event was the Halt interruption event.");
}
-
+
if (stop_state == lldb::eStateStopped)
{
// Between the time we initiated the Halt and the time we delivered it, the process could have
// already finished its job. Check that here:
-
+
if (thread->IsThreadPlanDone (thread_plan_sp.get()))
{
if (log)
log->PutCString ("Process::RunThreadPlan(): Even though we timed out, the call plan was done. "
"Exiting wait loop.");
- return_value = eExecutionCompleted;
+ return_value = eExpressionCompleted;
back_to_top = false;
break;
}
-
+
if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
{
if (log)
@@ -5491,11 +5503,11 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
if (log)
log->PutCString ("Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting.");
- return_value = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
back_to_top = false;
break;
}
-
+
if (before_first_timeout)
{
// Set all the other threads to run, and return to the top of the loop, which will continue;
@@ -5512,7 +5524,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// Running all threads failed, so return Interrupted.
if (log)
log->PutCString("Process::RunThreadPlan(): running all threads timed out.");
- return_value = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
back_to_top = false;
break;
}
@@ -5522,7 +5534,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{ if (log)
log->PutCString("Process::RunThreadPlan(): halt said it succeeded, but I got no event. "
"I'm getting out of here passing Interrupted.");
- return_value = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
back_to_top = false;
break;
}
@@ -5533,14 +5545,14 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
continue;
}
}
-
+
if (!back_to_top || try_halt_again > num_retries)
break;
else
continue;
}
} // END WAIT LOOP
-
+
// If we had to start up a temporary private state thread to run this thread plan, shut it down now.
if (IS_VALID_LLDB_HOST_THREAD(backup_private_state_thread))
{
@@ -5554,23 +5566,23 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
m_public_state.SetValueNoLock(old_state);
}
-
+
// Restore the thread state if we are going to discard the plan execution. There are three cases where this
// could happen:
// 1) The execution successfully completed
// 2) We hit a breakpoint, and ignore_breakpoints was true
// 3) We got some other error, and discard_on_error was true
- bool should_unwind = (return_value == eExecutionInterrupted && options.DoesUnwindOnError())
- || (return_value == eExecutionHitBreakpoint && options.DoesIgnoreBreakpoints());
-
- if (return_value == eExecutionCompleted
+ bool should_unwind = (return_value == eExpressionInterrupted && options.DoesUnwindOnError())
+ || (return_value == eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints());
+
+ if (return_value == eExpressionCompleted
|| should_unwind)
{
thread_plan_sp->RestoreThreadState();
}
-
+
// Now do some processing on the results of the run:
- if (return_value == eExecutionInterrupted || return_value == eExecutionHitBreakpoint)
+ if (return_value == eExpressionInterrupted || return_value == eExpressionHitBreakpoint)
{
if (log)
{
@@ -5585,7 +5597,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
StreamString ts;
const char *event_explanation = NULL;
-
+
do
{
if (!event_sp)
@@ -5607,7 +5619,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
event_explanation = "<no event data>";
break;
}
-
+
Process *process = event_data->GetProcessSP().get();
if (!process)
@@ -5615,34 +5627,34 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
event_explanation = "<no process>";
break;
}
-
+
ThreadList &thread_list = process->GetThreadList();
-
+
uint32_t num_threads = thread_list.GetSize();
uint32_t thread_index;
-
+
ts.Printf("<%u threads> ", num_threads);
-
+
for (thread_index = 0;
thread_index < num_threads;
++thread_index)
{
Thread *thread = thread_list.GetThreadAtIndex(thread_index).get();
-
+
if (!thread)
{
ts.Printf("<?> ");
continue;
}
-
+
ts.Printf("<0x%4.4" PRIx64 " ", thread->GetID());
RegisterContext *register_context = thread->GetRegisterContext().get();
-
+
if (register_context)
ts.Printf("[ip 0x%" PRIx64 "] ", register_context->GetPC());
else
ts.Printf("[ip unknown] ");
-
+
lldb::StopInfoSP stop_info_sp = thread->GetStopInfo();
if (stop_info_sp)
{
@@ -5652,35 +5664,37 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
}
ts.Printf(">");
}
-
+
event_explanation = ts.GetData();
}
} while (0);
-
+
if (event_explanation)
log->Printf("Process::RunThreadPlan(): execution interrupted: %s %s", s.GetData(), event_explanation);
else
log->Printf("Process::RunThreadPlan(): execution interrupted: %s", s.GetData());
}
-
+
if (should_unwind)
{
if (log)
- log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - discarding thread plans up to %p.", thread_plan_sp.get());
+ log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - discarding thread plans up to %p.",
+ static_cast<void*>(thread_plan_sp.get()));
thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
thread_plan_sp->SetPrivate (orig_plan_private);
}
else
{
if (log)
- log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - for plan: %p not discarding.", thread_plan_sp.get());
+ log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - for plan: %p not discarding.",
+ static_cast<void*>(thread_plan_sp.get()));
}
}
- else if (return_value == eExecutionSetupError)
+ else if (return_value == eExpressionSetupError)
{
if (log)
log->PutCString("Process::RunThreadPlan(): execution set up error.");
-
+
if (options.DoesUnwindOnError())
{
thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
@@ -5693,13 +5707,13 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
if (log)
log->PutCString("Process::RunThreadPlan(): thread plan is done");
- return_value = eExecutionCompleted;
+ return_value = eExpressionCompleted;
}
else if (thread->WasThreadPlanDiscarded (thread_plan_sp.get()))
{
if (log)
log->PutCString("Process::RunThreadPlan(): thread plan was discarded");
- return_value = eExecutionDiscarded;
+ return_value = eExpressionDiscarded;
}
else
{
@@ -5714,7 +5728,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
}
}
}
-
+
// Thread we ran the function in may have gone away because we ran the target
// Check that it's still there, and if it is put it back in the context. Also restore the
// frame in the context if it is still present.
@@ -5723,10 +5737,10 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
exe_ctx.SetFrameSP (thread->GetFrameWithStackID (ctx_frame_id));
}
-
+
// Also restore the current process'es selected frame & thread, since this function calling may
// be done behind the user's back.
-
+
if (selected_tid != LLDB_INVALID_THREAD_ID)
{
if (GetThreadList().SetSelectedThreadByIndexID (selected_tid) && selected_stack_id.IsValid())
@@ -5739,46 +5753,52 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
}
}
}
-
+
// If the process exited during the run of the thread plan, notify everyone.
-
+
if (event_to_broadcast_sp)
{
if (log)
log->PutCString("Process::RunThreadPlan(): rebroadcasting event.");
BroadcastEvent(event_to_broadcast_sp);
}
-
+
return return_value;
}
const char *
-Process::ExecutionResultAsCString (ExecutionResults result)
+Process::ExecutionResultAsCString (ExpressionResults result)
{
const char *result_name;
switch (result)
{
- case eExecutionCompleted:
- result_name = "eExecutionCompleted";
+ case eExpressionCompleted:
+ result_name = "eExpressionCompleted";
break;
- case eExecutionDiscarded:
- result_name = "eExecutionDiscarded";
+ case eExpressionDiscarded:
+ result_name = "eExpressionDiscarded";
break;
- case eExecutionInterrupted:
- result_name = "eExecutionInterrupted";
+ case eExpressionInterrupted:
+ result_name = "eExpressionInterrupted";
break;
- case eExecutionHitBreakpoint:
- result_name = "eExecutionHitBreakpoint";
+ case eExpressionHitBreakpoint:
+ result_name = "eExpressionHitBreakpoint";
break;
- case eExecutionSetupError:
- result_name = "eExecutionSetupError";
+ case eExpressionSetupError:
+ result_name = "eExpressionSetupError";
break;
- case eExecutionTimedOut:
- result_name = "eExecutionTimedOut";
+ case eExpressionParseError:
+ result_name = "eExpressionParseError";
break;
- case eExecutionStoppedForDebug:
- result_name = "eExecutionStoppedForDebug";
+ case eExpressionResultUnavailable:
+ result_name = "eExpressionResultUnavailable";
+ break;
+ case eExpressionTimedOut:
+ result_name = "eExpressionTimedOut";
+ break;
+ case eExpressionStoppedForDebug:
+ result_name = "eExpressionStoppedForDebug";
break;
}
return result_name;
@@ -5823,25 +5843,47 @@ Process::GetThreadStatus (Stream &strm,
{
size_t num_thread_infos_dumped = 0;
- Mutex::Locker locker (GetThreadList().GetMutex());
- const size_t num_threads = GetThreadList().GetSize();
+ // You can't hold the thread list lock while calling Thread::GetStatus. That very well might run code (e.g. if we need it
+ // to get return values or arguments.) For that to work the process has to be able to acquire it. So instead copy the thread
+ // ID's, and look them up one by one:
+
+ uint32_t num_threads;
+ std::vector<uint32_t> thread_index_array;
+ //Scope for thread list locker;
+ {
+ Mutex::Locker locker (GetThreadList().GetMutex());
+ ThreadList &curr_thread_list = GetThreadList();
+ num_threads = curr_thread_list.GetSize();
+ uint32_t idx;
+ thread_index_array.resize(num_threads);
+ for (idx = 0; idx < num_threads; ++idx)
+ thread_index_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetID();
+ }
+
for (uint32_t i = 0; i < num_threads; i++)
{
- Thread *thread = GetThreadList().GetThreadAtIndex(i).get();
- if (thread)
+ ThreadSP thread_sp(GetThreadList().FindThreadByID(thread_index_array[i]));
+ if (thread_sp)
{
if (only_threads_with_stop_reason)
{
- StopInfoSP stop_info_sp = thread->GetStopInfo();
+ StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
if (stop_info_sp.get() == NULL || !stop_info_sp->IsValid())
continue;
}
- thread->GetStatus (strm,
+ thread_sp->GetStatus (strm,
start_frame,
num_frames,
num_frames_with_source);
++num_thread_infos_dumped;
}
+ else
+ {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::GetThreadStatus - thread 0x" PRIu64 " vanished while running Thread::GetStatus.");
+
+ }
}
return num_thread_infos_dumped;
}
@@ -5897,6 +5939,10 @@ Process::Flush ()
void
Process::DidExec ()
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("Process::%s()", __FUNCTION__);
+
Target &target = GetTarget();
target.CleanupProcess ();
target.ClearModules(false);
@@ -5905,6 +5951,7 @@ Process::DidExec ()
m_system_runtime_ap.reset();
m_os_ap.reset();
m_dyld_ap.reset();
+ m_jit_loaders_ap.reset();
m_image_tokens.clear();
m_allocated_memory_cache.Clear();
m_language_runtimes.clear();
@@ -5955,3 +6002,14 @@ Process::ResolveIndirectFunction(const Address *address, Error &error)
return function_addr;
}
+void
+Process::ModulesDidLoad (ModuleList &module_list)
+{
+ SystemRuntime *sys_runtime = GetSystemRuntime();
+ if (sys_runtime)
+ {
+ sys_runtime->ModulesDidLoad (module_list);
+ }
+
+ GetJITLoaders().ModulesDidLoad (module_list);
+}
diff --git a/source/Target/ProcessInfo.cpp b/source/Target/ProcessInfo.cpp
new file mode 100644
index 000000000000..22da2c6a2a29
--- /dev/null
+++ b/source/Target/ProcessInfo.cpp
@@ -0,0 +1,138 @@
+//===-- ProcessInfo.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/Target/ProcessInfo.h"
+
+// C Includes
+#include <limits.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+ProcessInfo::ProcessInfo () :
+ m_executable (),
+ m_arguments (),
+ m_environment (),
+ m_uid (UINT32_MAX),
+ m_gid (UINT32_MAX),
+ m_arch(),
+ m_pid (LLDB_INVALID_PROCESS_ID)
+{
+}
+
+ProcessInfo::ProcessInfo (const char *name, const ArchSpec &arch, lldb::pid_t pid) :
+ m_executable (name, false),
+ m_arguments (),
+ m_environment(),
+ m_uid (UINT32_MAX),
+ m_gid (UINT32_MAX),
+ m_arch (arch),
+ m_pid (pid)
+{
+}
+
+void
+ProcessInfo::Clear ()
+{
+ m_executable.Clear();
+ m_arguments.Clear();
+ m_environment.Clear();
+ m_uid = UINT32_MAX;
+ m_gid = UINT32_MAX;
+ m_arch.Clear();
+ m_pid = LLDB_INVALID_PROCESS_ID;
+}
+
+const char *
+ProcessInfo::GetName() const
+{
+ return m_executable.GetFilename().GetCString();
+}
+
+size_t
+ProcessInfo::GetNameLength() const
+{
+ return m_executable.GetFilename().GetLength();
+}
+
+void
+ProcessInfo::SetExecutableFile (const FileSpec &exe_file, bool add_exe_file_as_first_arg)
+{
+ if (exe_file)
+ {
+ m_executable = exe_file;
+ if (add_exe_file_as_first_arg)
+ {
+ char filename[PATH_MAX];
+ if (exe_file.GetPath(filename, sizeof(filename)))
+ m_arguments.InsertArgumentAtIndex (0, filename);
+ }
+ }
+ else
+ {
+ m_executable.Clear();
+ }
+}
+
+const char *
+ProcessInfo::GetArg0 () const
+{
+ if (m_arg0.empty())
+ return NULL;
+ return m_arg0.c_str();
+}
+
+void
+ProcessInfo::SetArg0 (const char *arg)
+{
+ if (arg && arg[0])
+ m_arg0 = arg;
+ else
+ m_arg0.clear();
+}
+
+void
+ProcessInfo::SetArguments (char const **argv, bool first_arg_is_executable)
+{
+ m_arguments.SetArguments (argv);
+
+ // Is the first argument the executable?
+ if (first_arg_is_executable)
+ {
+ const char *first_arg = m_arguments.GetArgumentAtIndex (0);
+ if (first_arg)
+ {
+ // Yes the first argument is an executable, set it as the executable
+ // in the launch options. Don't resolve the file path as the path
+ // could be a remote platform path
+ const bool resolve = false;
+ m_executable.SetFile(first_arg, resolve);
+ }
+ }
+}
+void
+ProcessInfo::SetArguments (const Args& args, bool first_arg_is_executable)
+{
+ // Copy all arguments
+ m_arguments = args;
+
+ // Is the first argument the executable?
+ if (first_arg_is_executable)
+ {
+ const char *first_arg = m_arguments.GetArgumentAtIndex (0);
+ if (first_arg)
+ {
+ // Yes the first argument is an executable, set it as the executable
+ // in the launch options. Don't resolve the file path as the path
+ // could be a remote platform path
+ const bool resolve = false;
+ m_executable.SetFile(first_arg, resolve);
+ }
+ }
+}
diff --git a/source/Target/ProcessLaunchInfo.cpp b/source/Target/ProcessLaunchInfo.cpp
new file mode 100644
index 000000000000..830f1470ed98
--- /dev/null
+++ b/source/Target/ProcessLaunchInfo.cpp
@@ -0,0 +1,459 @@
+//===-- ProcessLaunchInfo.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/Host/Config.h"
+
+#ifndef LLDB_DISABLE_POSIX
+#include <spawn.h>
+#endif
+
+#include "lldb/Target/ProcessLaunchInfo.h"
+#include "lldb/Target/FileAction.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------------
+// ProcessLaunchInfo member functions
+//----------------------------------------------------------------------------
+
+ProcessLaunchInfo::ProcessLaunchInfo () :
+ ProcessInfo(),
+ m_working_dir (),
+ m_plugin_name (),
+ m_shell (),
+ m_flags (0),
+ m_file_actions (),
+ m_pty (),
+ m_resume_count (0),
+ m_monitor_callback (NULL),
+ m_monitor_callback_baton (NULL),
+ m_monitor_signals (false),
+ m_hijack_listener_sp ()
+{
+}
+
+ProcessLaunchInfo::ProcessLaunchInfo(const char *stdin_path, const char *stdout_path, const char *stderr_path,
+ const char *working_directory, uint32_t launch_flags)
+ : ProcessInfo()
+ , m_working_dir()
+ , m_plugin_name()
+ , m_shell()
+ , m_flags(launch_flags)
+ , m_file_actions()
+ , m_pty()
+ , m_resume_count(0)
+ , m_monitor_callback(NULL)
+ , m_monitor_callback_baton(NULL)
+ , m_monitor_signals(false)
+ , m_hijack_listener_sp()
+{
+ if (stdin_path)
+ {
+ FileAction file_action;
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDIN_FILENO, stdin_path, read, write))
+ AppendFileAction (file_action);
+ }
+ if (stdout_path)
+ {
+ FileAction file_action;
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDOUT_FILENO, stdout_path, read, write))
+ AppendFileAction (file_action);
+ }
+ if (stderr_path)
+ {
+ FileAction file_action;
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDERR_FILENO, stderr_path, read, write))
+ AppendFileAction (file_action);
+ }
+ if (working_directory)
+ SetWorkingDirectory(working_directory);
+}
+
+bool
+ProcessLaunchInfo::AppendCloseFileAction (int fd)
+{
+ FileAction file_action;
+ if (file_action.Close (fd))
+ {
+ AppendFileAction (file_action);
+ return true;
+ }
+ return false;
+}
+
+bool
+ProcessLaunchInfo::AppendDuplicateFileAction (int fd, int dup_fd)
+{
+ FileAction file_action;
+ if (file_action.Duplicate (fd, dup_fd))
+ {
+ AppendFileAction (file_action);
+ return true;
+ }
+ return false;
+}
+
+bool
+ProcessLaunchInfo::AppendOpenFileAction (int fd, const char *path, bool read, bool write)
+{
+ FileAction file_action;
+ if (file_action.Open (fd, path, read, write))
+ {
+ AppendFileAction (file_action);
+ return true;
+ }
+ return false;
+}
+
+bool
+ProcessLaunchInfo::AppendSuppressFileAction (int fd, bool read, bool write)
+{
+ FileAction file_action;
+ if (file_action.Open (fd, "/dev/null", read, write))
+ {
+ AppendFileAction (file_action);
+ return true;
+ }
+ return false;
+}
+
+const FileAction *
+ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const
+{
+ if (idx < m_file_actions.size())
+ return &m_file_actions[idx];
+ return NULL;
+}
+
+const FileAction *
+ProcessLaunchInfo::GetFileActionForFD(int fd) const
+{
+ for (size_t idx=0, count=m_file_actions.size(); idx < count; ++idx)
+ {
+ if (m_file_actions[idx].GetFD () == fd)
+ return &m_file_actions[idx];
+ }
+ return NULL;
+}
+
+const char *
+ProcessLaunchInfo::GetWorkingDirectory () const
+{
+ if (m_working_dir.empty())
+ return NULL;
+ return m_working_dir.c_str();
+}
+
+void
+ProcessLaunchInfo::SetWorkingDirectory (const char *working_dir)
+{
+ if (working_dir && working_dir[0])
+ m_working_dir.assign (working_dir);
+ else
+ m_working_dir.clear();
+}
+
+const char *
+ProcessLaunchInfo::GetProcessPluginName () const
+{
+ if (m_plugin_name.empty())
+ return NULL;
+ return m_plugin_name.c_str();
+}
+
+void
+ProcessLaunchInfo::SetProcessPluginName (const char *plugin)
+{
+ if (plugin && plugin[0])
+ m_plugin_name.assign (plugin);
+ else
+ m_plugin_name.clear();
+}
+
+const char *
+ProcessLaunchInfo::GetShell () const
+{
+ if (m_shell.empty())
+ return NULL;
+ return m_shell.c_str();
+}
+
+void
+ProcessLaunchInfo::SetShell (const char * path)
+{
+ if (path && path[0])
+ {
+ m_shell.assign (path);
+ m_flags.Set (lldb::eLaunchFlagLaunchInShell);
+ }
+ else
+ {
+ m_shell.clear();
+ m_flags.Clear (lldb::eLaunchFlagLaunchInShell);
+ }
+}
+
+void
+ProcessLaunchInfo::SetLaunchInSeparateProcessGroup (bool separate)
+{
+ if (separate)
+ m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
+ else
+ m_flags.Clear (lldb::eLaunchFlagLaunchInSeparateProcessGroup);
+
+}
+
+void
+ProcessLaunchInfo::Clear ()
+{
+ ProcessInfo::Clear();
+ m_working_dir.clear();
+ m_plugin_name.clear();
+ m_shell.clear();
+ m_flags.Clear();
+ m_file_actions.clear();
+ m_resume_count = 0;
+ m_hijack_listener_sp.reset();
+}
+
+void
+ProcessLaunchInfo::SetMonitorProcessCallback (Host::MonitorChildProcessCallback callback,
+ void *baton,
+ bool monitor_signals)
+{
+ m_monitor_callback = callback;
+ m_monitor_callback_baton = baton;
+ m_monitor_signals = monitor_signals;
+}
+
+bool
+ProcessLaunchInfo::MonitorProcess () const
+{
+ if (m_monitor_callback && ProcessIDIsValid())
+ {
+ Host::StartMonitoringChildProcess (m_monitor_callback,
+ m_monitor_callback_baton,
+ GetProcessID(),
+ m_monitor_signals);
+ return true;
+ }
+ return false;
+}
+
+void
+ProcessLaunchInfo::SetDetachOnError (bool enable)
+{
+ if (enable)
+ m_flags.Set(lldb::eLaunchFlagDetachOnError);
+ else
+ m_flags.Clear(lldb::eLaunchFlagDetachOnError);
+}
+
+void
+ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
+{
+ // If nothing for stdin or stdout or stderr was specified, then check the process for any default
+ // settings that were set with "settings set"
+ if (GetFileActionForFD(STDIN_FILENO) == NULL || GetFileActionForFD(STDOUT_FILENO) == NULL ||
+ GetFileActionForFD(STDERR_FILENO) == NULL)
+ {
+ if (m_flags.Test(eLaunchFlagDisableSTDIO))
+ {
+ AppendSuppressFileAction (STDIN_FILENO , true, false);
+ AppendSuppressFileAction (STDOUT_FILENO, false, true);
+ AppendSuppressFileAction (STDERR_FILENO, false, true);
+ }
+ else
+ {
+ // Check for any values that might have gotten set with any of:
+ // (lldb) settings set target.input-path
+ // (lldb) settings set target.output-path
+ // (lldb) settings set target.error-path
+ FileSpec in_path;
+ FileSpec out_path;
+ FileSpec err_path;
+ if (target)
+ {
+ in_path = target->GetStandardInputPath();
+ out_path = target->GetStandardOutputPath();
+ err_path = target->GetStandardErrorPath();
+ }
+
+ char path[PATH_MAX];
+ if (in_path && in_path.GetPath(path, sizeof(path)))
+ AppendOpenFileAction(STDIN_FILENO, path, true, false);
+
+ if (out_path && out_path.GetPath(path, sizeof(path)))
+ AppendOpenFileAction(STDOUT_FILENO, path, false, true);
+
+ if (err_path && err_path.GetPath(path, sizeof(path)))
+ AppendOpenFileAction(STDERR_FILENO, path, false, true);
+
+ if (default_to_use_pty && (!in_path || !out_path || !err_path)) {
+ if (m_pty.OpenFirstAvailableMaster(O_RDWR| O_NOCTTY, NULL, 0)) {
+ const char *slave_path = m_pty.GetSlaveName(NULL, 0);
+
+ if (!in_path) {
+ AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
+ }
+
+ if (!out_path) {
+ AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
+ }
+
+ if (!err_path) {
+ AppendOpenFileAction(STDERR_FILENO, slave_path, false, true);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+bool
+ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
+ bool localhost,
+ bool will_debug,
+ bool first_arg_is_full_shell_command,
+ int32_t num_resumes)
+{
+ error.Clear();
+
+ if (GetFlags().Test (eLaunchFlagLaunchInShell))
+ {
+ const char *shell_executable = GetShell();
+ if (shell_executable)
+ {
+ char shell_resolved_path[PATH_MAX];
+
+ if (localhost)
+ {
+ FileSpec shell_filespec (shell_executable, true);
+
+ if (!shell_filespec.Exists())
+ {
+ // Resolve the path in case we just got "bash", "sh" or "tcsh"
+ if (!shell_filespec.ResolveExecutableLocation ())
+ {
+ error.SetErrorStringWithFormat("invalid shell path '%s'", shell_executable);
+ return false;
+ }
+ }
+ shell_filespec.GetPath (shell_resolved_path, sizeof(shell_resolved_path));
+ shell_executable = shell_resolved_path;
+ }
+
+ const char **argv = GetArguments().GetConstArgumentVector ();
+ if (argv == NULL || argv[0] == NULL)
+ return false;
+ Args shell_arguments;
+ std::string safe_arg;
+ shell_arguments.AppendArgument (shell_executable);
+ shell_arguments.AppendArgument ("-c");
+ StreamString shell_command;
+ if (will_debug)
+ {
+ // Add a modified PATH environment variable in case argv[0]
+ // is a relative path
+ const char *argv0 = argv[0];
+ if (argv0 && (argv0[0] != '/' && argv0[0] != '~'))
+ {
+ // We have a relative path to our executable which may not work if
+ // we just try to run "a.out" (without it being converted to "./a.out")
+ const char *working_dir = GetWorkingDirectory();
+ // Be sure to put quotes around PATH's value in case any paths have spaces...
+ std::string new_path("PATH=\"");
+ const size_t empty_path_len = new_path.size();
+
+ if (working_dir && working_dir[0])
+ {
+ new_path += working_dir;
+ }
+ else
+ {
+ char current_working_dir[PATH_MAX];
+ const char *cwd = getcwd(current_working_dir, sizeof(current_working_dir));
+ if (cwd && cwd[0])
+ new_path += cwd;
+ }
+ const char *curr_path = getenv("PATH");
+ if (curr_path)
+ {
+ if (new_path.size() > empty_path_len)
+ new_path += ':';
+ new_path += curr_path;
+ }
+ new_path += "\" ";
+ shell_command.PutCString(new_path.c_str());
+ }
+
+ shell_command.PutCString ("exec");
+
+ // Only Apple supports /usr/bin/arch being able to specify the architecture
+ if (GetArchitecture().IsValid() && // Valid architecture
+ GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple && // Apple only
+ GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h
+ {
+ shell_command.Printf(" /usr/bin/arch -arch %s", GetArchitecture().GetArchitectureName());
+ // Set the resume count to 2:
+ // 1 - stop in shell
+ // 2 - stop in /usr/bin/arch
+ // 3 - then we will stop in our program
+ SetResumeCount(num_resumes + 1);
+ }
+ else
+ {
+ // Set the resume count to 1:
+ // 1 - stop in shell
+ // 2 - then we will stop in our program
+ SetResumeCount(num_resumes);
+ }
+ }
+
+ if (first_arg_is_full_shell_command)
+ {
+ // There should only be one argument that is the shell command itself to be used as is
+ if (argv[0] && !argv[1])
+ shell_command.Printf("%s", argv[0]);
+ else
+ return false;
+ }
+ else
+ {
+ for (size_t i=0; argv[i] != NULL; ++i)
+ {
+ const char *arg = Args::GetShellSafeArgument (argv[i], safe_arg);
+ shell_command.Printf(" %s", arg);
+ }
+ }
+ shell_arguments.AppendArgument (shell_command.GetString().c_str());
+ m_executable.SetFile(shell_executable, false);
+ m_arguments = shell_arguments;
+ return true;
+ }
+ else
+ {
+ error.SetErrorString ("invalid shell path");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("not launching in shell");
+ }
+ return false;
+}
diff --git a/source/Target/Queue.cpp b/source/Target/Queue.cpp
index 2b9d2a0ed9a4..7cfa6fa5582f 100644
--- a/source/Target/Queue.cpp
+++ b/source/Target/Queue.cpp
@@ -23,7 +23,8 @@ Queue::Queue (ProcessSP process_sp, lldb::queue_id_t queue_id, const char *queue
m_running_work_items_count(0),
m_pending_work_items_count(0),
m_pending_items(),
- m_dispatch_queue_t_addr(LLDB_INVALID_ADDRESS)
+ m_dispatch_queue_t_addr(LLDB_INVALID_ADDRESS),
+ m_kind (eQueueKindUnknown)
{
if (queue_name)
m_queue_name = queue_name;
@@ -125,3 +126,15 @@ Queue::GetPendingItems ()
}
return m_pending_items;
}
+
+lldb::QueueKind
+Queue::GetKind ()
+{
+ return m_kind;
+}
+
+void
+Queue::SetKind (lldb::QueueKind kind)
+{
+ m_kind = kind;
+}
diff --git a/source/Target/QueueItem.cpp b/source/Target/QueueItem.cpp
index bb6762829ca6..002187b8d204 100644
--- a/source/Target/QueueItem.cpp
+++ b/source/Target/QueueItem.cpp
@@ -15,10 +15,13 @@
using namespace lldb;
using namespace lldb_private;
-QueueItem::QueueItem (QueueSP queue_sp) :
+QueueItem::QueueItem (QueueSP queue_sp, ProcessSP process_sp, lldb::addr_t item_ref, lldb_private::Address address) :
m_queue_wp (),
+ m_process_wp (),
+ m_item_ref (item_ref),
+ m_address (address),
+ m_have_fetched_entire_item (false),
m_kind (eQueueItemKindUnknown),
- m_address (),
m_item_that_enqueued_this_ref (LLDB_INVALID_ADDRESS),
m_enqueueing_thread_id (LLDB_INVALID_THREAD_ID),
m_enqueueing_queue_id (LLDB_INVALID_QUEUE_ID),
@@ -30,6 +33,7 @@ QueueItem::QueueItem (QueueSP queue_sp) :
m_target_queue_label()
{
m_queue_wp = queue_sp;
+ m_process_wp = process_sp;
}
QueueItem::~QueueItem ()
@@ -37,8 +41,9 @@ QueueItem::~QueueItem ()
}
QueueItemKind
-QueueItem::GetKind() const
+QueueItem::GetKind()
{
+ FetchEntireItem ();
return m_kind;
}
@@ -63,6 +68,7 @@ QueueItem::SetAddress (Address addr)
ThreadSP
QueueItem::GetExtendedBacktraceThread (ConstString type)
{
+ FetchEntireItem ();
ThreadSP return_thread;
QueueSP queue_sp = m_queue_wp.lock();
if (queue_sp)
@@ -75,3 +81,76 @@ QueueItem::GetExtendedBacktraceThread (ConstString type)
}
return return_thread;
}
+
+lldb::addr_t
+QueueItem::GetItemThatEnqueuedThis ()
+{
+ FetchEntireItem ();
+ return m_item_that_enqueued_this_ref;
+}
+
+lldb::tid_t
+QueueItem::GetEnqueueingThreadID ()
+{
+ FetchEntireItem ();
+ return m_enqueueing_thread_id;
+}
+
+lldb::queue_id_t
+QueueItem::GetEnqueueingQueueID ()
+{
+ FetchEntireItem ();
+ return m_enqueueing_queue_id;
+}
+
+uint32_t
+QueueItem::GetStopID ()
+{
+ FetchEntireItem ();
+ return m_stop_id;
+}
+
+std::vector<lldb::addr_t> &
+QueueItem::GetEnqueueingBacktrace ()
+{
+ FetchEntireItem ();
+ return m_backtrace;
+}
+
+std::string
+QueueItem::GetThreadLabel ()
+{
+ FetchEntireItem ();
+ return m_thread_label;
+}
+
+std::string
+QueueItem::GetQueueLabel ()
+{
+ FetchEntireItem ();
+ return m_queue_label;
+}
+
+
+ProcessSP
+QueueItem::GetProcessSP()
+{
+ return m_process_wp.lock ();
+}
+
+void
+QueueItem::FetchEntireItem()
+{
+ if (m_have_fetched_entire_item == true)
+ return;
+ ProcessSP process_sp = m_process_wp.lock();
+ if (process_sp)
+ {
+ SystemRuntime *runtime = process_sp->GetSystemRuntime();
+ if (runtime)
+ {
+ runtime->CompleteQueueItem (this, m_item_ref);
+ m_have_fetched_entire_item = true;
+ }
+ }
+}
diff --git a/source/Target/RegisterContext.cpp b/source/Target/RegisterContext.cpp
index 93dce3ea0edc..97f6f21c53c8 100644
--- a/source/Target/RegisterContext.cpp
+++ b/source/Target/RegisterContext.cpp
@@ -82,7 +82,7 @@ RegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx
}
const RegisterInfo *
-RegisterContext::GetRegisterInfo (uint32_t kind, uint32_t num)
+RegisterContext::GetRegisterInfo (lldb::RegisterKind kind, uint32_t num)
{
const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num);
if (reg_num == LLDB_INVALID_REGNUM)
@@ -488,7 +488,7 @@ RegisterContext::CalculateExecutionContext (ExecutionContext &exe_ctx)
bool
-RegisterContext::ConvertBetweenRegisterKinds (int source_rk, uint32_t source_regnum, int target_rk, uint32_t& target_regnum)
+RegisterContext::ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint32_t source_regnum, lldb::RegisterKind target_rk, uint32_t& target_regnum)
{
const uint32_t num_registers = GetRegisterCount();
for (uint32_t reg = 0; reg < num_registers; ++reg)
diff --git a/source/Target/SectionLoadHistory.cpp b/source/Target/SectionLoadHistory.cpp
index 527168ce42af..1e5c4175a2bf 100644
--- a/source/Target/SectionLoadHistory.cpp
+++ b/source/Target/SectionLoadHistory.cpp
@@ -47,15 +47,7 @@ SectionLoadHistory::GetLastStopID() const
SectionLoadList *
SectionLoadHistory::GetSectionLoadListForStopID (uint32_t stop_id, bool read_only)
{
- if (m_stop_id_to_section_load_list.empty())
- {
- SectionLoadListSP section_load_list_sp(new SectionLoadList());
- if (stop_id == eStopIDNow)
- stop_id = 0;
- m_stop_id_to_section_load_list[stop_id] = section_load_list_sp;
- return section_load_list_sp.get();
- }
- else
+ if (!m_stop_id_to_section_load_list.empty())
{
if (read_only)
{
@@ -65,7 +57,7 @@ SectionLoadHistory::GetSectionLoadListForStopID (uint32_t stop_id, bool read_onl
if (stop_id == eStopIDNow)
{
// If we are asking for the latest and greatest value, it is always
- // at the end of our list becuase that will be the highest stop ID.
+ // at the end of our list because that will be the highest stop ID.
StopIDToSectionLoadList::reverse_iterator rpos = m_stop_id_to_section_load_list.rbegin();
return rpos->second.get();
}
@@ -105,13 +97,18 @@ SectionLoadHistory::GetSectionLoadListForStopID (uint32_t stop_id, bool read_onl
return section_load_list_sp.get();
}
}
- return NULL;
+ SectionLoadListSP section_load_list_sp(new SectionLoadList());
+ if (stop_id == eStopIDNow)
+ stop_id = 0;
+ m_stop_id_to_section_load_list[stop_id] = section_load_list_sp;
+ return section_load_list_sp.get();
}
SectionLoadList &
SectionLoadHistory::GetCurrentSectionLoadList ()
{
const bool read_only = true;
+ Mutex::Locker locker(m_mutex);
SectionLoadList *section_load_list = GetSectionLoadListForStopID (eStopIDNow, read_only);
assert(section_load_list != NULL);
return *section_load_list;
diff --git a/source/Target/SectionLoadList.cpp b/source/Target/SectionLoadList.cpp
index 82f52f9db1b5..da3aea5034d1 100644
--- a/source/Target/SectionLoadList.cpp
+++ b/source/Target/SectionLoadList.cpp
@@ -81,19 +81,17 @@ SectionLoadList::SetSectionLoadAddress (const lldb::SectionSP &section, addr_t l
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_VERBOSE));
ModuleSP module_sp (section->GetModule());
-
+
if (module_sp)
{
if (log)
{
const FileSpec &module_file_spec (module_sp->GetFileSpec());
log->Printf ("SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64 ") module = %p",
- __FUNCTION__,
- section.get(),
+ __FUNCTION__, static_cast<void*>(section.get()),
module_file_spec.GetPath().c_str(),
- section->GetName().AsCString(),
- load_addr,
- module_sp.get());
+ section->GetName().AsCString(), load_addr,
+ static_cast<void*>(module_sp.get()));
}
if (section->GetByteSize() == 0)
@@ -118,7 +116,7 @@ SectionLoadList::SetSectionLoadAddress (const lldb::SectionSP &section, addr_t l
{
// Some sections are ok to overlap, and for others we should warn. When
// we have multiple load addresses that correspond to a section, we will
- // allways attribute the section to the be last section that claims it
+ // always attribute the section to the be last section that claims it
// exists at that address. Sometimes it is ok for more that one section
// to be loaded at a specific load address, and other times it isn't.
// The "warn_multiple" parameter tells us if we should warn in this case
@@ -155,8 +153,7 @@ SectionLoadList::SetSectionLoadAddress (const lldb::SectionSP &section, addr_t l
if (log)
{
log->Printf ("SectionLoadList::%s (section = %p (%s), load_addr = 0x%16.16" PRIx64 ") error: module has been deleted",
- __FUNCTION__,
- section.get(),
+ __FUNCTION__, static_cast<void*>(section.get()),
section->GetName().AsCString(),
load_addr);
}
@@ -177,14 +174,13 @@ SectionLoadList::SetSectionUnloaded (const lldb::SectionSP &section_sp)
{
const FileSpec &module_file_spec (section_sp->GetModule()->GetFileSpec());
log->Printf ("SectionLoadList::%s (section = %p (%s.%s))",
- __FUNCTION__,
- section_sp.get(),
+ __FUNCTION__, static_cast<void*>(section_sp.get()),
module_file_spec.GetPath().c_str(),
section_sp->GetName().AsCString());
}
Mutex::Locker locker(m_mutex);
-
+
sect_to_addr_collection::iterator sta_pos = m_sect_to_addr.find(section_sp.get());
if (sta_pos != m_sect_to_addr.end())
{
@@ -209,11 +205,9 @@ SectionLoadList::SetSectionUnloaded (const lldb::SectionSP &section_sp, addr_t l
{
const FileSpec &module_file_spec (section_sp->GetModule()->GetFileSpec());
log->Printf ("SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64 ")",
- __FUNCTION__,
- section_sp.get(),
+ __FUNCTION__, static_cast<void*>(section_sp.get()),
module_file_spec.GetPath().c_str(),
- section_sp->GetName().AsCString(),
- load_addr);
+ section_sp->GetName().AsCString(), load_addr);
}
bool erased = false;
Mutex::Locker locker(m_mutex);
@@ -223,7 +217,7 @@ SectionLoadList::SetSectionUnloaded (const lldb::SectionSP &section_sp, addr_t l
erased = true;
m_sect_to_addr.erase (sta_pos);
}
-
+
addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr);
if (ats_pos != m_addr_to_sect.end())
{
@@ -287,7 +281,8 @@ SectionLoadList::Dump (Stream &s, Target *target)
addr_to_sect_collection::const_iterator pos, end;
for (pos = m_addr_to_sect.begin(), end = m_addr_to_sect.end(); pos != end; ++pos)
{
- s.Printf("addr = 0x%16.16" PRIx64 ", section = %p: ", pos->first, pos->second.get());
+ s.Printf("addr = 0x%16.16" PRIx64 ", section = %p: ",
+ pos->first, static_cast<void*>(pos->second.get()));
pos->second->Dump (&s, target, 0);
}
}
diff --git a/source/Target/StackFrame.cpp b/source/Target/StackFrame.cpp
index a936a57d048d..e497b176ccfe 100644
--- a/source/Target/StackFrame.cpp
+++ b/source/Target/StackFrame.cpp
@@ -360,7 +360,7 @@ StackFrame::GetSymbolContext (uint32_t resolve_scope)
}
- // Resolve our PC to section offset if we haven't alreday done so
+ // Resolve our PC to section offset if we haven't already done so
// and if we don't have a module. The resolved address section will
// contain the module to which it belongs
if (!m_sc.module_sp && m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR))
@@ -861,7 +861,7 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
valobj_sp->GetTypeName().AsCString("<invalid type>"),
var_expr_path_strm.GetString().c_str());
}
- else if (child_index >= synthetic->GetNumChildren() /* synthetic does not have that many values */)
+ else if (static_cast<uint32_t>(child_index) >= synthetic->GetNumChildren() /* synthetic does not have that many values */)
{
valobj_sp->GetExpressionPath (var_expr_path_strm, false);
error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",
@@ -937,7 +937,7 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
valobj_sp->GetTypeName().AsCString("<invalid type>"),
var_expr_path_strm.GetString().c_str());
}
- else if (child_index >= synthetic->GetNumChildren() /* synthetic does not have that many values */)
+ else if (static_cast<uint32_t>(child_index) >= synthetic->GetNumChildren() /* synthetic does not have that many values */)
{
valobj_sp->GetExpressionPath (var_expr_path_strm, false);
error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",
@@ -1444,13 +1444,12 @@ StackFrame::GetStatus (Stream& strm,
const uint32_t source_lines_after = debugger.GetStopSourceLineCount(false);
disasm_display = debugger.GetStopDisassemblyDisplay ();
- if (source_lines_before > 0 || source_lines_after > 0)
+ GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry);
+ if (m_sc.comp_unit && m_sc.line_entry.IsValid())
{
- GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry);
-
- if (m_sc.comp_unit && m_sc.line_entry.IsValid())
+ have_source = true;
+ if (source_lines_before > 0 || source_lines_after > 0)
{
- have_source = true;
target->GetSourceManager().DisplaySourceLinesWithLineNumbers (m_sc.line_entry.file,
m_sc.line_entry.line,
source_lines_before,
diff --git a/source/Target/StackFrameList.cpp b/source/Target/StackFrameList.cpp
index 631a77bd4951..99234dc61f1d 100644
--- a/source/Target/StackFrameList.cpp
+++ b/source/Target/StackFrameList.cpp
@@ -269,7 +269,7 @@ StackFrameList::GetFramesUpTo(uint32_t end_idx)
StreamFile s(stdout, false);
#endif
// If we are hiding some frames from the outside world, we need to add those onto the total count of
- // frames to fetch. However, we don't need ot do that if end_idx is 0 since in that case we always
+ // frames to fetch. However, we don't need to do that if end_idx is 0 since in that case we always
// get the first concrete frame and all the inlined frames below it... And of course, if end_idx is
// UINT32_MAX that means get all, so just do that...
@@ -491,7 +491,7 @@ StackFrameList::Dump (Stream *s)
for (pos = begin; pos != end; ++pos)
{
StackFrame *frame = (*pos).get();
- s->Printf("%p: ", frame);
+ s->Printf("%p: ", static_cast<void*>(frame));
if (frame)
{
frame->GetStackID().Dump (s);
diff --git a/source/Target/StackID.cpp b/source/Target/StackID.cpp
index 9e8c315d0704..ca337f914406 100644
--- a/source/Target/StackID.cpp
+++ b/source/Target/StackID.cpp
@@ -24,11 +24,12 @@ using namespace lldb_private;
void
StackID::Dump (Stream *s)
{
- s->Printf("StackID (pc = 0x%16.16" PRIx64 ", cfa = 0x%16.16" PRIx64 ", symbol_scope = %p", (uint64_t)m_pc, (uint64_t)m_cfa, m_symbol_scope);
+ s->Printf("StackID (pc = 0x%16.16" PRIx64 ", cfa = 0x%16.16" PRIx64 ", symbol_scope = %p",
+ m_pc, m_cfa, static_cast<void*>(m_symbol_scope));
if (m_symbol_scope)
{
SymbolContext sc;
-
+
m_symbol_scope->CalculateSymbolContext (&sc);
if (sc.block)
s->Printf(" (Block {0x%8.8" PRIx64 "})", sc.block->GetID());
diff --git a/source/Target/StopInfo.cpp b/source/Target/StopInfo.cpp
index 3664e8f0c738..a37a4079ff11 100644
--- a/source/Target/StopInfo.cpp
+++ b/source/Target/StopInfo.cpp
@@ -108,7 +108,6 @@ namespace lldb_private
class StopInfoBreakpoint : public StopInfo
{
public:
-
StopInfoBreakpoint (Thread &thread, break_id_t break_id) :
StopInfo (thread, break_id),
m_description(),
@@ -121,7 +120,7 @@ public:
{
StoreBPInfo();
}
-
+
StopInfoBreakpoint (Thread &thread, break_id_t break_id, bool should_stop) :
StopInfo (thread, break_id),
m_description(),
@@ -161,7 +160,7 @@ public:
virtual ~StopInfoBreakpoint ()
{
}
-
+
virtual StopReason
GetStopReason () const
{
@@ -199,7 +198,7 @@ public:
}
return false;
}
-
+
virtual bool
DoShouldNotify (Event *event_ptr)
{
@@ -252,7 +251,7 @@ public:
}
}
}
-
+
strm.Printf("breakpoint ");
bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief);
m_description.swap (strm.GetString());
@@ -290,7 +289,7 @@ public:
strm.Printf("breakpoint site %" PRIi64 " which has been deleted - unknown address", m_value);
else
strm.Printf("breakpoint site %" PRIi64 " which has been deleted - was at 0x%" PRIx64, m_value, m_address);
-
+
m_description.swap (strm.GetString());
}
}
@@ -307,20 +306,20 @@ protected:
assert (m_should_stop_is_valid);
return m_should_stop;
}
-
+
virtual void
PerformAction (Event *event_ptr)
{
if (!m_should_perform_action)
return;
m_should_perform_action = false;
-
+
ThreadSP thread_sp (m_thread_wp.lock());
if (thread_sp)
{
- Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
-
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS | LIBLLDB_LOG_STEP);
+
if (!thread_sp->IsValid())
{
// This shouldn't ever happen, but just in case, don't do more harm.
@@ -332,13 +331,13 @@ protected:
m_should_stop_is_valid = true;
return;
}
-
+
BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
-
+
if (bp_site_sp)
{
size_t num_owners = bp_site_sp->GetNumberOfOwners();
-
+
if (num_owners == 0)
{
m_should_stop = true;
@@ -354,7 +353,7 @@ protected:
// we're going to restart, without running the rest of the callbacks. And in this case we will
// end up not stopping even if another location said we should stop. But that's better than not
// running all the callbacks.
-
+
m_should_stop = false;
ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
@@ -367,7 +366,7 @@ protected:
// TODO: We can keep a list of the breakpoints we've seen while running expressions in the nested
// PerformAction calls that can arise when the action runs a function that hits another breakpoint,
// and only stop running commands when we see the same breakpoint hit a second time.
-
+
m_should_stop_is_valid = true;
if (log)
log->Printf ("StopInfoBreakpoint::PerformAction - Hit a breakpoint while running an expression,"
@@ -398,12 +397,12 @@ protected:
"running function, skipping commands and conditions to prevent recursion.");
return;
}
-
+
StoppointCallbackContext context (event_ptr, exe_ctx, false);
-
+
// Let's copy the breakpoint locations out of the site and store them in a local list. That way if
// one of the breakpoint actions changes the site, then we won't be operating on a bad list.
-
+
BreakpointLocationCollection site_locations;
for (size_t j = 0; j < num_owners; j++)
site_locations.Add(bp_site_sp->GetOwnerAtIndex(j));
@@ -411,11 +410,11 @@ protected:
for (size_t j = 0; j < num_owners; j++)
{
lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j);
-
+
// If another action disabled this breakpoint or its location, then don't run the actions.
if (!bp_loc_sp->IsEnabled() || !bp_loc_sp->GetBreakpoint().IsEnabled())
continue;
-
+
// The breakpoint site may have many locations associated with it, not all of them valid for
// this thread. Skip the ones that aren't:
if (!bp_loc_sp->ValidForThisThread(thread_sp.get()))
@@ -424,18 +423,20 @@ protected:
{
StreamString s;
bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief);
- log->Printf ("Breakpoint %s hit on thread 0x%llx but it was not for this thread, continuing.", s.GetData(), thread_sp->GetID());
+ log->Printf ("Breakpoint %s hit on thread 0x%llx but it was not for this thread, continuing.",
+ s.GetData(),
+ static_cast<unsigned long long>(thread_sp->GetID()));
}
continue;
}
// First run the condition for the breakpoint. If that says we should stop, then we'll run
// the callback for the breakpoint. If the callback says we shouldn't stop that will win.
-
+
if (bp_loc_sp->GetConditionText() != NULL)
{
Error condition_error;
bool condition_says_stop = bp_loc_sp->ConditionSaysStop(exe_ctx, condition_error);
-
+
if (!condition_error.Success())
{
Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
@@ -448,12 +449,10 @@ protected:
const char *err_str = condition_error.AsCString("<Unknown Error>");
if (log)
log->Printf("Error evaluating condition: \"%s\"\n", err_str);
-
+
error_sp->PutCString (err_str);
error_sp->EOL();
error_sp->Flush();
- // If the condition fails to be parsed or run, we should stop.
- condition_says_stop = true;
}
else
{
@@ -461,36 +460,39 @@ protected:
{
StreamString s;
bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief);
- log->Printf ("Condition evaluated for breakpoint %s on thread 0x%llx conditon_says_stop: %i.", s.GetData(), thread_sp->GetID(), condition_says_stop);
+ log->Printf ("Condition evaluated for breakpoint %s on thread 0x%llx conditon_says_stop: %i.",
+ s.GetData(),
+ static_cast<unsigned long long>(thread_sp->GetID()),
+ condition_says_stop);
}
if (!condition_says_stop)
continue;
}
}
-
+
bool callback_says_stop;
-
+
// FIXME: For now the callbacks have to run in async mode - the first time we restart we need
// to get out of there. So set it here.
// When we figure out how to nest breakpoint hits then this will change.
-
+
Debugger &debugger = thread_sp->CalculateTarget()->GetDebugger();
bool old_async = debugger.GetAsyncExecution();
debugger.SetAsyncExecution (true);
-
+
callback_says_stop = bp_loc_sp->InvokeCallback (&context);
-
+
debugger.SetAsyncExecution (old_async);
-
+
if (callback_says_stop)
m_should_stop = true;
-
+
// If we are going to stop for this breakpoint, then remove the breakpoint.
if (callback_says_stop && bp_loc_sp && bp_loc_sp->GetBreakpoint().IsOneShot())
{
thread_sp->GetProcess()->GetTarget().RemoveBreakpointByID (bp_loc_sp->GetBreakpoint().GetID());
}
-
+
// Also make sure that the callback hasn't continued the target.
// If it did, when we'll set m_should_start to false and get out of here.
if (HasTargetRunSinceMe ())
@@ -706,7 +708,7 @@ protected:
{
// We need to make sure the user sees any parse errors in their condition, so we'll hook the
// constructor errors up to the debugger's Async I/O.
- ExecutionResults result_code;
+ ExpressionResults result_code;
EvaluateExpressionOptions expr_options;
expr_options.SetUnwindOnError(true);
expr_options.SetIgnoreBreakpoints(true);
@@ -718,7 +720,7 @@ protected:
NULL,
result_value_sp,
error);
- if (result_code == eExecutionCompleted)
+ if (result_code == eExpressionCompleted)
{
if (result_value_sp)
{
@@ -995,10 +997,11 @@ class StopInfoThreadPlan : public StopInfo
{
public:
- StopInfoThreadPlan (ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp) :
+ StopInfoThreadPlan (ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp, ClangExpressionVariableSP &expression_variable_sp) :
StopInfo (plan_sp->GetThread(), LLDB_INVALID_UID),
m_plan_sp (plan_sp),
- m_return_valobj_sp (return_valobj_sp)
+ m_return_valobj_sp (return_valobj_sp),
+ m_expression_variable_sp (expression_variable_sp)
{
}
@@ -1030,6 +1033,12 @@ public:
return m_return_valobj_sp;
}
+ ClangExpressionVariableSP
+ GetExpressionVariable()
+ {
+ return m_expression_variable_sp;
+ }
+
protected:
virtual bool
ShouldStop (Event *event_ptr)
@@ -1043,6 +1052,7 @@ protected:
private:
ThreadPlanSP m_plan_sp;
ValueObjectSP m_return_valobj_sp;
+ ClangExpressionVariableSP m_expression_variable_sp;
};
class StopInfoExec : public StopInfo
@@ -1121,9 +1131,11 @@ StopInfo::CreateStopReasonToTrace (Thread &thread)
}
StopInfoSP
-StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp, ValueObjectSP return_valobj_sp)
+StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp,
+ ValueObjectSP return_valobj_sp,
+ ClangExpressionVariableSP expression_variable_sp)
{
- return StopInfoSP (new StopInfoThreadPlan (plan_sp, return_valobj_sp));
+ return StopInfoSP (new StopInfoThreadPlan (plan_sp, return_valobj_sp, expression_variable_sp));
}
StopInfoSP
@@ -1149,3 +1161,15 @@ StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp)
else
return ValueObjectSP();
}
+
+ClangExpressionVariableSP
+StopInfo::GetExpressionVariable(StopInfoSP &stop_info_sp)
+{
+ if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonPlanComplete)
+ {
+ StopInfoThreadPlan *plan_stop_info = static_cast<StopInfoThreadPlan *>(stop_info_sp.get());
+ return plan_stop_info->GetExpressionVariable();
+ }
+ else
+ return ClangExpressionVariableSP();
+}
diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp
index e7816266b415..d2d0b5098555 100644
--- a/source/Target/Target.cpp
+++ b/source/Target/Target.cpp
@@ -94,12 +94,12 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::Plat
SetEventName (eBroadcastBitModulesUnloaded, "modules-unloaded");
SetEventName (eBroadcastBitWatchpointChanged, "watchpoint-changed");
SetEventName (eBroadcastBitSymbolsLoaded, "symbols-loaded");
-
+
CheckInWithManager();
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Target::Target()", this);
+ log->Printf ("%p Target::Target()", static_cast<void*>(this));
if (m_arch.IsValid())
{
LogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET, "Target::Target created with architecture %s (%s)", m_arch.GetArchitectureName(), m_arch.GetTriple().getTriple().c_str());
@@ -113,7 +113,7 @@ Target::~Target()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Target::~Target()", this);
+ log->Printf ("%p Target::~Target()", static_cast<void*>(this));
DeleteCurrentProcess ();
}
@@ -486,9 +486,12 @@ Target::CreateFuncRegexBreakpoint (const FileSpecList *containingModules,
bool hardware)
{
SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, containingSourceFiles));
+ bool skip =
+ (skip_prologue == eLazyBoolCalculate) ? GetSkipPrologue()
+ : static_cast<bool>(skip_prologue);
BreakpointResolverSP resolver_sp(new BreakpointResolverName (NULL,
func_regex,
- skip_prologue == eLazyBoolCalculate ? GetSkipPrologue() : skip_prologue));
+ skip));
return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true);
}
@@ -635,7 +638,7 @@ Target::CreateWatchpoint(lldb::addr_t addr, size_t size, const ClangASTType *typ
if (!CheckIfWatchpointsExhausted(this, error))
{
if (!OptionGroupWatchpoint::IsWatchSizeSupported(size))
- error.SetErrorStringWithFormat("watch size of %zu is not supported", size);
+ error.SetErrorStringWithFormat("watch size of %" PRIu64 " is not supported", (uint64_t)size);
}
wp_sp.reset();
}
@@ -1010,10 +1013,10 @@ LoadScriptingResourceForModule (const ModuleSP &module_sp, Target *target)
target->GetDebugger().GetErrorFile()->Printf("unable to load scripting data for module %s - error reported was %s\n",
module_sp->GetFileSpec().GetFileNameStrippingExtension().GetCString(),
error.AsCString());
- if (feedback_stream.GetSize())
- target->GetDebugger().GetErrorFile()->Printf("%s\n",
- feedback_stream.GetData());
}
+ if (feedback_stream.GetSize())
+ target->GetDebugger().GetErrorFile()->Printf("%s\n",
+ feedback_stream.GetData());
}
void
@@ -1047,7 +1050,7 @@ Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files)
"Target::SetExecutableModule (executable = '%s')",
executable_sp->GetFileSpec().GetPath().c_str());
- m_images.Append(executable_sp); // The first image is our exectuable file
+ m_images.Append(executable_sp); // The first image is our executable file
// If we haven't set an architecture yet, reset our architecture based on what we found in the executable module.
if (!m_arch.IsValid())
@@ -1142,41 +1145,44 @@ void
Target::ModuleAdded (const ModuleList& module_list, const ModuleSP &module_sp)
{
// A module is being added to this target for the first time
- ModuleList my_module_list;
- my_module_list.Append(module_sp);
- LoadScriptingResourceForModule(module_sp, this);
- ModulesDidLoad (my_module_list);
+ if (m_valid)
+ {
+ ModuleList my_module_list;
+ my_module_list.Append(module_sp);
+ LoadScriptingResourceForModule(module_sp, this);
+ ModulesDidLoad (my_module_list);
+ }
}
void
Target::ModuleRemoved (const ModuleList& module_list, const ModuleSP &module_sp)
{
// A module is being added to this target for the first time
- ModuleList my_module_list;
- my_module_list.Append(module_sp);
- ModulesDidUnload (my_module_list, false);
+ if (m_valid)
+ {
+ ModuleList my_module_list;
+ my_module_list.Append(module_sp);
+ ModulesDidUnload (my_module_list, false);
+ }
}
void
Target::ModuleUpdated (const ModuleList& module_list, const ModuleSP &old_module_sp, const ModuleSP &new_module_sp)
{
// A module is replacing an already added module
- m_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced(old_module_sp, new_module_sp);
+ if (m_valid)
+ m_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced(old_module_sp, new_module_sp);
}
void
Target::ModulesDidLoad (ModuleList &module_list)
{
- if (module_list.GetSize())
+ if (m_valid && module_list.GetSize())
{
m_breakpoint_list.UpdateBreakpoints (module_list, true, false);
if (m_process_sp)
{
- SystemRuntime *sys_runtime = m_process_sp->GetSystemRuntime();
- if (sys_runtime)
- {
- sys_runtime->ModulesDidLoad (module_list);
- }
+ m_process_sp->ModulesDidLoad (module_list);
}
// TODO: make event data that packages up the module_list
BroadcastEvent (eBroadcastBitModulesLoaded, NULL);
@@ -1186,7 +1192,7 @@ Target::ModulesDidLoad (ModuleList &module_list)
void
Target::SymbolsDidLoad (ModuleList &module_list)
{
- if (module_list.GetSize())
+ if (m_valid && module_list.GetSize())
{
if (m_process_sp)
{
@@ -1206,7 +1212,7 @@ Target::SymbolsDidLoad (ModuleList &module_list)
void
Target::ModulesDidUnload (ModuleList &module_list, bool delete_locations)
{
- if (module_list.GetSize())
+ if (m_valid && module_list.GetSize())
{
m_breakpoint_list.UpdateBreakpoints (module_list, false, delete_locations);
// TODO: make event data that packages up the module_list
@@ -1255,7 +1261,7 @@ Target::ReadMemoryFromFileCache (const Address& addr, void *dst, size_t dst_len,
SectionSP section_sp (addr.GetSection());
if (section_sp)
{
- // If the contents of this section are encrypted, the on-disk file is unusuable. Read only from live memory.
+ // If the contents of this section are encrypted, the on-disk file is unusable. Read only from live memory.
if (section_sp->IsEncrypted())
{
error.SetErrorString("section is encrypted");
@@ -1320,7 +1326,7 @@ Target::ReadMemory (const Address& addr,
}
else
{
- // We have at least one section loaded. This can be becuase
+ // We have at least one section loaded. This can be because
// we have manually loaded some sections with "target modules load ..."
// or because we have have a live process that has sections loaded
// through the dynamic loader
@@ -1376,7 +1382,7 @@ Target::ReadMemory (const Address& addr,
}
// If the address is not section offset we have an address that
// doesn't resolve to any address in any currently loaded shared
- // libaries and we failed to read memory so there isn't anything
+ // libraries and we failed to read memory so there isn't anything
// more we can do. If it is section offset, we might be able to
// read cached memory from the object file.
if (!resolved_addr.IsSectionOffset())
@@ -1547,7 +1553,7 @@ Target::ReadPointerFromMemory (const Address& addr,
}
else
{
- // We have at least one section loaded. This can be becuase
+ // We have at least one section loaded. This can be because
// we have manually loaded some sections with "target modules load ..."
// or because we have have a live process that has sections loaded
// through the dynamic loader
@@ -1698,6 +1704,8 @@ Target::GetSharedModule (const ModuleSpec &module_spec, Error *error_ptr)
else
m_images.Append(module_sp);
}
+ else
+ module_sp.reset();
}
}
if (error_ptr)
@@ -1765,7 +1773,7 @@ Target::GetScratchClangASTContext(bool create_on_demand)
m_scratch_ast_context_ap.reset (new ClangASTContext(m_arch.GetTriple().str().c_str()));
m_scratch_ast_source_ap.reset (new ClangASTSource(shared_from_this()));
m_scratch_ast_source_ap->InstallASTContext(m_scratch_ast_context_ap->getASTContext());
- llvm::OwningPtr<clang::ExternalASTSource> proxy_ast_source(m_scratch_ast_source_ap->CreateProxy());
+ llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> proxy_ast_source(m_scratch_ast_source_ap->CreateProxy());
m_scratch_ast_context_ap->SetExternalSource(proxy_ast_source);
}
return m_scratch_ast_context_ap.get();
@@ -1850,7 +1858,7 @@ Target::GetTargetFromContexts (const ExecutionContext *exe_ctx_ptr, const Symbol
return target;
}
-ExecutionResults
+ExpressionResults
Target::EvaluateExpression
(
const char *expr_cstr,
@@ -1861,7 +1869,7 @@ Target::EvaluateExpression
{
result_valobj_sp.reset();
- ExecutionResults execution_results = eExecutionSetupError;
+ ExpressionResults execution_results = eExpressionSetupError;
if (expr_cstr == NULL || expr_cstr[0] == '\0')
return execution_results;
@@ -1896,7 +1904,7 @@ Target::EvaluateExpression
if (persistent_var_sp)
{
result_valobj_sp = persistent_var_sp->GetValueObject ();
- execution_results = eExecutionCompleted;
+ execution_results = eExpressionCompleted;
}
else
{
@@ -2363,7 +2371,8 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
if (!launch_info.GetArchitecture().IsValid())
launch_info.GetArchitecture() = GetArchitecture();
-
+
+ // If we're not already connected to the process, and if we have a platform that can launch a process for debugging, go ahead and do that here.
if (state != eStateConnected && platform_sp && platform_sp->CanDebugProcess ())
{
m_process_sp = GetPlatform()->DebugProcess (launch_info,
@@ -2380,10 +2389,12 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
}
else
{
+ // Use a Process plugin to construct the process.
const char *plugin_name = launch_info.GetProcessPluginName();
CreateProcess (listener, plugin_name, NULL);
}
-
+
+ // Since we didn't have a platform launch the process, launch it here.
if (m_process_sp)
error = m_process_sp->Launch (launch_info);
}
@@ -2409,9 +2420,14 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
m_process_sp->RestoreProcessEvents ();
error = m_process_sp->PrivateResume();
-
+
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()
+ m_process_sp->SyncIOHandler(2000);
+
if (synchronous_execution)
{
state = m_process_sp->WaitForProcessToStop (NULL, NULL, true, hijack_listener_sp.get());
@@ -2429,6 +2445,27 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
error = error2;
}
}
+ else if (state == eStateExited)
+ {
+ bool with_shell = launch_info.GetShell();
+ const int exit_status = m_process_sp->GetExitStatus();
+ const char *exit_desc = m_process_sp->GetExitDescription();
+#define LAUNCH_SHELL_MESSAGE "\n'r' and 'run' are aliases that default to launching through a shell.\nTry launching without going through a shell by using 'process launch'."
+ if (exit_desc && exit_desc[0])
+ {
+ if (with_shell)
+ error.SetErrorStringWithFormat ("process exited with status %i (%s)" LAUNCH_SHELL_MESSAGE, exit_status, exit_desc);
+ else
+ error.SetErrorStringWithFormat ("process exited with status %i (%s)", exit_status, exit_desc);
+ }
+ else
+ {
+ if (with_shell)
+ error.SetErrorStringWithFormat ("process exited with status %i" LAUNCH_SHELL_MESSAGE, exit_status);
+ else
+ error.SetErrorStringWithFormat ("process exited with status %i", exit_status);
+ }
+ }
else
{
error.SetErrorStringWithFormat ("initial process state wasn't stopped: %s", StateAsCString(state));
@@ -2616,6 +2653,7 @@ g_properties[] =
{ "input-path" , OptionValue::eTypeFileSpec , false, 0 , NULL, NULL, "The file/path to be used by the executable program for reading its standard input." },
{ "output-path" , OptionValue::eTypeFileSpec , false, 0 , NULL, NULL, "The file/path to be used by the executable program for writing its standard output." },
{ "error-path" , OptionValue::eTypeFileSpec , false, 0 , NULL, NULL, "The file/path to be used by the executable program for writing its standard error." },
+ { "detach-on-error" , OptionValue::eTypeBoolean , false, true , NULL, NULL, "debugserver will detach (rather than killing) a process if it loses connection with lldb." },
{ "disable-aslr" , OptionValue::eTypeBoolean , false, true , NULL, NULL, "Disable Address Space Layout Randomization (ASLR)" },
{ "disable-stdio" , OptionValue::eTypeBoolean , false, false , NULL, NULL, "Disable stdin/stdout for process (e.g. for a GUI application)" },
{ "inline-breakpoint-strategy" , OptionValue::eTypeEnum , false, eInlineBreakpointsHeaders , NULL, g_inline_breakpoint_enums, "The strategy to use when settings breakpoints by file and line. "
@@ -2662,6 +2700,7 @@ enum
ePropertyInputPath,
ePropertyOutputPath,
ePropertyErrorPath,
+ ePropertyDetachOnError,
ePropertyDisableASLR,
ePropertyDisableSTDIO,
ePropertyInlineStrategy,
@@ -2699,7 +2738,7 @@ public:
virtual const Property *
GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
{
- // When gettings the value for a key from the target options, we will always
+ // When getting the value for a key from the target options, we will always
// try and grab the setting from the current target if there is one. Else we just
// use the one from this instance.
if (idx == ePropertyEnvVars)
@@ -2845,6 +2884,20 @@ TargetProperties::SetDisableASLR (bool b)
}
bool
+TargetProperties::GetDetachOnError () const
+{
+ const uint32_t idx = ePropertyDetachOnError;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void
+TargetProperties::SetDetachOnError (bool b)
+{
+ const uint32_t idx = ePropertyDetachOnError;
+ m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
+}
+
+bool
TargetProperties::GetDisableSTDIO () const
{
const uint32_t idx = ePropertyDisableSTDIO;
diff --git a/source/Target/TargetList.cpp b/source/Target/TargetList.cpp
index c4da84fbf8be..5ee75ff74449 100644
--- a/source/Target/TargetList.cpp
+++ b/source/Target/TargetList.cpp
@@ -28,6 +28,8 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/TargetList.h"
+#include "llvm/ADT/SmallString.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -85,12 +87,31 @@ TargetList::CreateTarget (Debugger &debugger,
ArchSpec platform_arch(arch);
+ bool prefer_platform_arch = false;
+
+ CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
+ if (platform_options && platform_options->PlatformWasSpecified ())
+ {
+ const bool select_platform = true;
+ platform_sp = platform_options->CreatePlatformWithOptions (interpreter,
+ arch,
+ select_platform,
+ error,
+ platform_arch);
+ if (!platform_sp)
+ return error;
+ }
if (user_exe_path && user_exe_path[0])
{
ModuleSpecList module_specs;
ModuleSpec module_spec;
module_spec.GetFileSpec().SetFile(user_exe_path, true);
+
+ // Resolve the executable in case we are given a path to a application bundle
+ // like a .app bundle on MacOSX
+ Host::ResolveExecutableInBundle (module_spec.GetFileSpec());
+
lldb::offset_t file_offset = 0;
lldb::offset_t file_size = 0;
const size_t num_specs = ObjectFile::GetModuleSpecifications (module_spec.GetFileSpec(), file_offset, file_size, module_specs);
@@ -104,7 +125,17 @@ TargetList::CreateTarget (Debugger &debugger,
{
if (platform_arch.IsValid())
{
- if (!platform_arch.IsCompatibleMatch(matching_module_spec.GetArchitecture()))
+ if (platform_arch.IsCompatibleMatch(matching_module_spec.GetArchitecture()))
+ {
+ // If the OS or vendor weren't specified, then adopt the module's
+ // architecture so that the platform matching can be more accurate
+ if (!platform_arch.TripleOSWasSpecified() || !platform_arch.TripleVendorWasSpecified())
+ {
+ prefer_platform_arch = true;
+ platform_arch = matching_module_spec.GetArchitecture();
+ }
+ }
+ else
{
error.SetErrorStringWithFormat("the specified architecture '%s' is not compatible with '%s' in '%s'",
platform_arch.GetTriple().str().c_str(),
@@ -116,6 +147,7 @@ TargetList::CreateTarget (Debugger &debugger,
else
{
// Only one arch and none was specified
+ prefer_platform_arch = true;
platform_arch = matching_module_spec.GetArchitecture();
}
}
@@ -127,48 +159,114 @@ TargetList::CreateTarget (Debugger &debugger,
module_spec.GetArchitecture() = arch;
if (module_specs.FindMatchingModuleSpec(module_spec, matching_module_spec))
{
+ prefer_platform_arch = true;
platform_arch = matching_module_spec.GetArchitecture();
}
}
- // Don't just select the first architecture, we want to let the platform select
- // the best architecture first when there are multiple archs.
-// else
-// {
-// // No arch specified, select the first arch
-// if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec))
-// {
-// platform_arch = matching_module_spec.GetArchitecture();
-// }
-// }
+ else
+ {
+ // No architecture specified, check if there is only one platform for
+ // all of the architectures.
+
+ typedef std::vector<PlatformSP> PlatformList;
+ PlatformList platforms;
+ PlatformSP host_platform_sp = Platform::GetDefaultPlatform();
+ for (size_t i=0; i<num_specs; ++i)
+ {
+ ModuleSpec module_spec;
+ if (module_specs.GetModuleSpecAtIndex(i, module_spec))
+ {
+ // See if there was a selected platform and check that first
+ // since the user may have specified it.
+ if (platform_sp)
+ {
+ if (platform_sp->IsCompatibleArchitecture(module_spec.GetArchitecture(), false, NULL))
+ {
+ platforms.push_back(platform_sp);
+ continue;
+ }
+ }
+
+ // Next check the host platform it if wasn't already checked above
+ if (host_platform_sp && (!platform_sp || host_platform_sp->GetName() != platform_sp->GetName()))
+ {
+ if (host_platform_sp->IsCompatibleArchitecture(module_spec.GetArchitecture(), false, NULL))
+ {
+ platforms.push_back(host_platform_sp);
+ continue;
+ }
+ }
+
+ // Just find a platform that matches the architecture in the executable file
+ platforms.push_back(Platform::GetPlatformForArchitecture(module_spec.GetArchitecture(), nullptr));
+ }
+ }
+
+ Platform *platform_ptr = NULL;
+ for (const auto &the_platform_sp : platforms)
+ {
+ if (platform_ptr)
+ {
+ if (platform_ptr->GetName() != the_platform_sp->GetName())
+ {
+ platform_ptr = NULL;
+ break;
+ }
+ }
+ else
+ {
+ platform_ptr = the_platform_sp.get();
+ }
+ }
+
+ if (platform_ptr)
+ {
+ // All platforms for all modules in the exectuable match, so we can select this platform
+ platform_sp = platforms.front();
+ }
+ else
+ {
+ // More than one platform claims to support this file, so the --platform option must be specified
+ StreamString error_strm;
+ std::set<Platform *> platform_set;
+ error_strm.Printf ("more than one platform supports this executable (");
+ for (const auto &the_platform_sp : platforms)
+ {
+ if (platform_set.find(the_platform_sp.get()) == platform_set.end())
+ {
+ if (!platform_set.empty())
+ error_strm.PutCString(", ");
+ error_strm.PutCString(the_platform_sp->GetName().GetCString());
+ platform_set.insert(the_platform_sp.get());
+ }
+ }
+ error_strm.Printf("), use the --platform option to specify a platform");
+ error.SetErrorString(error_strm.GetString().c_str());
+ return error;
+ }
+ }
}
}
}
- CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
- if (platform_options)
- {
- if (platform_options->PlatformWasSpecified ())
- {
- const bool select_platform = true;
- platform_sp = platform_options->CreatePlatformWithOptions (interpreter,
- arch,
- select_platform,
- error,
- platform_arch);
- if (!platform_sp)
- return error;
- }
- }
-
if (!platform_sp)
{
// Get the current platform and make sure it is compatible with the
// current architecture if we have a valid architecture.
platform_sp = debugger.GetPlatformList().GetSelectedPlatform ();
- if (arch.IsValid() && !platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch))
+ if (!prefer_platform_arch && arch.IsValid())
{
- platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch);
+ if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch))
+ platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch);
+ }
+ else if (platform_arch.IsValid())
+ {
+ // if "arch" isn't valid, yet "platform_arch" is, it means we have an executable file with
+ // a single architecture which should be used
+ ArchSpec fixed_platform_arch;
+ if (!platform_sp->IsCompatibleArchitecture(platform_arch, false, &fixed_platform_arch))
+ platform_sp = Platform::GetPlatformForArchitecture(platform_arch, &fixed_platform_arch);
}
}
@@ -200,17 +298,10 @@ TargetList::CreateTarget (Debugger &debugger,
ArchSpec arch(specified_arch);
- if (platform_sp)
+ if (arch.IsValid())
{
- if (arch.IsValid())
- {
- if (!platform_sp->IsCompatibleArchitecture(arch, false, NULL))
- platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch);
- }
- }
- else if (arch.IsValid())
- {
- platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch);
+ if (!platform_sp || !platform_sp->IsCompatibleArchitecture(arch, false, NULL))
+ platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch);
}
if (!platform_sp)
@@ -224,15 +315,13 @@ TargetList::CreateTarget (Debugger &debugger,
{
// we want to expand the tilde but we don't want to resolve any symbolic links
// so we can't use the FileSpec constructor's resolve flag
- char unglobbed_path[PATH_MAX];
- unglobbed_path[0] = '\0';
-
- size_t return_count = FileSpec::ResolveUsername(user_exe_path, unglobbed_path, sizeof(unglobbed_path));
-
- if (return_count == 0 || return_count >= sizeof(unglobbed_path))
- ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", user_exe_path);
+ llvm::SmallString<64> unglobbed_path(user_exe_path);
+ FileSpec::ResolveUsername(unglobbed_path);
- file = FileSpec(unglobbed_path, false);
+ if (unglobbed_path.empty())
+ file = FileSpec(user_exe_path, false);
+ else
+ file = FileSpec(unglobbed_path.c_str(), false);
}
bool user_exe_path_is_bundle = false;
diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp
index 39f269952882..a445517da6a8 100644
--- a/source/Target/Thread.cpp
+++ b/source/Target/Thread.cpp
@@ -26,6 +26,7 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
@@ -61,6 +62,9 @@ Thread::GetGlobalProperties()
static PropertyDefinition
g_properties[] =
{
+ { "step-in-avoid-nodebug", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, step-in will not stop in functions with no debug information." },
+ { "step-out-avoid-nodebug", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, when step-in/step-out/step-over leave the current frame, they will continue to step out till they come to a function with "
+ "debug information. Passing a frame argument to step-out will override this option." },
{ "step-avoid-regexp", OptionValue::eTypeRegex , true , REG_EXTENDED, "^std::", NULL, "A regular expression defining functions step-in won't stop in." },
{ "step-avoid-libraries", OptionValue::eTypeFileSpecList , true , REG_EXTENDED, NULL, NULL, "A list of libraries that source stepping won't stop in." },
{ "trace-thread", OptionValue::eTypeBoolean, false, false, NULL, NULL, "If true, this thread will single-step and log execution." },
@@ -68,6 +72,8 @@ g_properties[] =
};
enum {
+ ePropertyStepInAvoidsNoDebug,
+ ePropertyStepOutAvoidsNoDebug,
ePropertyStepAvoidRegex,
ePropertyStepAvoidLibraries,
ePropertyEnableThreadTrace
@@ -93,7 +99,7 @@ public:
virtual const Property *
GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
{
- // When gettings the value for a key from the thread options, we will always
+ // When getting the value for a key from the thread options, we will always
// try and grab the setting from the current thread if there is one. Else we just
// use the one from this instance.
if (exe_ctx)
@@ -151,6 +157,21 @@ ThreadProperties::GetTraceEnabledState() const
return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
}
+bool
+ThreadProperties::GetStepInAvoidsNoDebug() const
+{
+ const uint32_t idx = ePropertyStepInAvoidsNoDebug;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+bool
+ThreadProperties::GetStepOutAvoidsNoDebug() const
+{
+ const uint32_t idx = ePropertyStepOutAvoidsNoDebug;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+
//------------------------------------------------------------------
// Thread Event Data
//------------------------------------------------------------------
@@ -250,14 +271,14 @@ Thread::GetStaticBroadcasterClass ()
return class_name;
}
-Thread::Thread (Process &process, lldb::tid_t tid) :
+Thread::Thread (Process &process, lldb::tid_t tid, bool use_invalid_index_id) :
ThreadProperties (false),
UserID (tid),
Broadcaster(&process.GetTarget().GetDebugger(), Thread::GetStaticBroadcasterClass().AsCString()),
m_process_wp (process.shared_from_this()),
m_stop_info_sp (),
m_stop_info_stop_id (0),
- m_index_id (process.GetNextThreadIndexID(tid)),
+ m_index_id (use_invalid_index_id ? LLDB_INVALID_INDEX32 : process.GetNextThreadIndexID(tid)),
m_reg_context_sp (),
m_state (eStateUnloaded),
m_state_mutex (Mutex::eMutexTypeRecursive),
@@ -271,11 +292,14 @@ Thread::Thread (Process &process, lldb::tid_t tid) :
m_temporary_resume_state (eStateRunning),
m_unwinder_ap (),
m_destroy_called (false),
- m_override_should_notify (eLazyBoolCalculate)
+ m_override_should_notify (eLazyBoolCalculate),
+ m_extended_info_fetched (false),
+ m_extended_info ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Thread::Thread(tid = 0x%4.4" PRIx64 ")", this, GetID());
+ log->Printf ("%p Thread::Thread(tid = 0x%4.4" PRIx64 ")",
+ static_cast<void*>(this), GetID());
CheckInWithManager();
QueueFundamentalPlan(true);
@@ -286,7 +310,8 @@ Thread::~Thread()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Thread::~Thread(tid = 0x%4.4" PRIx64 ")", this, GetID());
+ log->Printf ("%p Thread::~Thread(tid = 0x%4.4" PRIx64 ")",
+ static_cast<void*>(this), GetID());
/// If you hit this assert, it means your derived class forgot to call DoDestroy in its destructor.
assert (m_destroy_called);
}
@@ -395,7 +420,7 @@ Thread::GetStopInfo ()
const uint32_t stop_id = process_sp ? process_sp->GetStopID() : UINT32_MAX;
if (plan_sp && plan_sp->PlanSucceeded())
{
- return StopInfo::CreateStopReasonWithPlan (plan_sp, GetReturnValueObject());
+ return StopInfo::CreateStopReasonWithPlan (plan_sp, GetReturnValueObject(), GetExpressionVariable());
}
else
{
@@ -475,7 +500,10 @@ Thread::SetStopInfo (const lldb::StopInfoSP &stop_info_sp)
m_stop_info_stop_id = UINT32_MAX;
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
if (log)
- log->Printf("%p: tid = 0x%" PRIx64 ": stop info = %s (stop_id = %u)\n", this, GetID(), stop_info_sp ? stop_info_sp->GetDescription() : "<NULL>", m_stop_info_stop_id);
+ log->Printf("%p: tid = 0x%" PRIx64 ": stop info = %s (stop_id = %u)",
+ static_cast<void*>(this), GetID(),
+ stop_info_sp ? stop_info_sp->GetDescription() : "<NULL>",
+ m_stop_info_stop_id);
}
void
@@ -723,31 +751,27 @@ bool
Thread::ShouldStop (Event* event_ptr)
{
ThreadPlan *current_plan = GetCurrentPlan();
-
+
bool should_stop = true;
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
-
+
if (GetResumeState () == eStateSuspended)
{
if (log)
log->Printf ("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", should_stop = 0 (ignore since thread was suspended)",
- __FUNCTION__,
- GetID (),
- GetProtocolID());
+ __FUNCTION__, GetID (), GetProtocolID());
return false;
}
-
+
if (GetTemporaryResumeState () == eStateSuspended)
{
if (log)
log->Printf ("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", should_stop = 0 (ignore since thread was suspended)",
- __FUNCTION__,
- GetID (),
- GetProtocolID());
+ __FUNCTION__, GetID (), GetProtocolID());
return false;
}
-
+
// Based on the current thread plan and process stop info, check if this
// thread caused the process to stop. NOTE: this must take place before
// the plan is moved from the current plan stack to the completed plan
@@ -756,31 +780,29 @@ Thread::ShouldStop (Event* event_ptr)
{
if (log)
log->Printf ("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", pc = 0x%16.16" PRIx64 ", should_stop = 0 (ignore since no stop reason)",
- __FUNCTION__,
- GetID (),
- GetProtocolID(),
+ __FUNCTION__, GetID (), GetProtocolID(),
GetRegisterContext() ? GetRegisterContext()->GetPC() : LLDB_INVALID_ADDRESS);
return false;
}
-
+
if (log)
{
log->Printf ("Thread::%s(%p) for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", pc = 0x%16.16" PRIx64,
- __FUNCTION__,
- this,
- GetID (),
+ __FUNCTION__, static_cast<void*>(this), GetID (),
GetProtocolID (),
- GetRegisterContext() ? GetRegisterContext()->GetPC() : LLDB_INVALID_ADDRESS);
+ GetRegisterContext()
+ ? GetRegisterContext()->GetPC()
+ : LLDB_INVALID_ADDRESS);
log->Printf ("^^^^^^^^ Thread::ShouldStop Begin ^^^^^^^^");
StreamString s;
s.IndentMore();
DumpThreadPlans(&s);
log->Printf ("Plan stack initial state:\n%s", s.GetData());
}
-
+
// The top most plan always gets to do the trace log...
current_plan->DoTraceLog ();
-
+
// First query the stop info's ShouldStopSynchronous. This handles "synchronous" stop reasons, for example the breakpoint
// command on internal breakpoints. If a synchronous stop reason says we should not stop, then we don't have to
// do any more work on this stop.
@@ -823,15 +845,15 @@ Thread::ShouldStop (Event* event_ptr)
if (plan_ptr->PlanExplainsStop(event_ptr))
{
should_stop = plan_ptr->ShouldStop (event_ptr);
-
+
// plan_ptr explains the stop, next check whether plan_ptr is done, if so, then we should take it
// and all the plans below it off the stack.
-
+
if (plan_ptr->MischiefManaged())
{
// We're going to pop the plans up to and including the plan that explains the stop.
ThreadPlan *prev_plan_ptr = GetPreviousPlan (plan_ptr);
-
+
do
{
if (should_stop)
@@ -848,21 +870,22 @@ Thread::ShouldStop (Event* event_ptr)
}
else
done_processing_current_plan = true;
-
+
break;
}
}
}
}
-
+
if (!done_processing_current_plan)
{
bool over_ride_stop = current_plan->ShouldAutoContinue(event_ptr);
-
+
if (log)
- log->Printf("Plan %s explains stop, auto-continue %i.", current_plan->GetName(), over_ride_stop);
-
+ log->Printf("Plan %s explains stop, auto-continue %i.",
+ current_plan->GetName(), over_ride_stop);
+
// We're starting from the base plan, so just let it decide;
if (PlanIsBasePlan(current_plan))
{
@@ -878,10 +901,11 @@ Thread::ShouldStop (Event* event_ptr)
{
if (PlanIsBasePlan(current_plan))
break;
-
+
should_stop = current_plan->ShouldStop(event_ptr);
if (log)
- log->Printf("Plan %s should stop: %d.", current_plan->GetName(), should_stop);
+ log->Printf("Plan %s should stop: %d.",
+ current_plan->GetName(), should_stop);
if (current_plan->MischiefManaged())
{
if (should_stop)
@@ -913,7 +937,7 @@ Thread::ShouldStop (Event* event_ptr)
}
}
}
-
+
if (over_ride_stop)
should_stop = false;
@@ -921,7 +945,7 @@ Thread::ShouldStop (Event* event_ptr)
// by hitting a breakpoint during a step-over - then do some step/finish/etc operations that wind up
// past the end point condition of the initial plan. We don't want to strand the original plan on the stack,
// This code clears stale plans off the stack.
-
+
if (should_stop)
{
ThreadPlan *plan_ptr = GetCurrentPlan();
@@ -930,16 +954,17 @@ Thread::ShouldStop (Event* event_ptr)
bool stale = plan_ptr->IsPlanStale ();
ThreadPlan *examined_plan = plan_ptr;
plan_ptr = GetPreviousPlan (examined_plan);
-
+
if (stale)
{
if (log)
- log->Printf("Plan %s being discarded in cleanup, it says it is already done.", examined_plan->GetName());
+ log->Printf("Plan %s being discarded in cleanup, it says it is already done.",
+ examined_plan->GetName());
DiscardThreadPlansUpToPlan(examined_plan);
}
}
}
-
+
}
if (log)
@@ -1016,37 +1041,33 @@ Vote
Thread::ShouldReportRun (Event* event_ptr)
{
StateType thread_state = GetResumeState ();
-
+
if (thread_state == eStateSuspended
|| thread_state == eStateInvalid)
{
return eVoteNoOpinion;
}
-
+
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (m_completed_plan_stack.size() > 0)
{
// Don't use GetCompletedPlan here, since that suppresses private plans.
if (log)
log->Printf ("Current Plan for thread %d(%p) (0x%4.4" PRIx64 ", %s): %s being asked whether we should report run.",
- GetIndexID(),
- this,
- GetID(),
+ GetIndexID(), static_cast<void*>(this), GetID(),
StateAsCString(GetTemporaryResumeState()),
m_completed_plan_stack.back()->GetName());
-
+
return m_completed_plan_stack.back()->ShouldReportRun (event_ptr);
}
else
{
if (log)
log->Printf ("Current Plan for thread %d(%p) (0x%4.4" PRIx64 ", %s): %s being asked whether we should report run.",
- GetIndexID(),
- this,
- GetID(),
+ GetIndexID(), static_cast<void*>(this), GetID(),
StateAsCString(GetTemporaryResumeState()),
GetCurrentPlan()->GetName());
-
+
return GetCurrentPlan()->ShouldReportRun (event_ptr);
}
}
@@ -1069,7 +1090,7 @@ Thread::PushPlan (ThreadPlanSP &thread_plan_sp)
if (!thread_plan_sp->GetThreadPlanTracer())
thread_plan_sp->SetThreadPlanTracer(m_plan_stack.back()->GetThreadPlanTracer());
m_plan_stack.push_back (thread_plan_sp);
-
+
thread_plan_sp->DidPush();
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
@@ -1078,8 +1099,7 @@ Thread::PushPlan (ThreadPlanSP &thread_plan_sp)
StreamString s;
thread_plan_sp->GetDescription (&s, lldb::eDescriptionLevelFull);
log->Printf("Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".",
- this,
- s.GetData(),
+ static_cast<void*>(this), s.GetData(),
thread_plan_sp->GetThread().GetID());
}
}
@@ -1164,6 +1184,22 @@ Thread::GetReturnValueObject ()
return ValueObjectSP();
}
+ClangExpressionVariableSP
+Thread::GetExpressionVariable ()
+{
+ if (!m_completed_plan_stack.empty())
+ {
+ for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--)
+ {
+ ClangExpressionVariableSP expression_variable_sp;
+ expression_variable_sp = m_completed_plan_stack[i]->GetExpressionVariable();
+ if (expression_variable_sp)
+ return expression_variable_sp;
+ }
+ }
+ return ClangExpressionVariableSP();
+}
+
bool
Thread::IsThreadPlanDone (ThreadPlan *plan)
{
@@ -1265,15 +1301,14 @@ Thread::DiscardThreadPlansUpToPlan (ThreadPlan *up_to_plan_ptr)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (log)
- {
- log->Printf("Discarding thread plans for thread tid = 0x%4.4" PRIx64 ", up to %p", GetID(), up_to_plan_ptr);
- }
+ log->Printf("Discarding thread plans for thread tid = 0x%4.4" PRIx64 ", up to %p",
+ GetID(), static_cast<void*>(up_to_plan_ptr));
int stack_size = m_plan_stack.size();
-
+
// If the input plan is NULL, discard all plans. Otherwise make sure this plan is in the
// stack, and if so discard up to and including it.
-
+
if (up_to_plan_ptr == NULL)
{
for (int i = stack_size - 1; i > 0; i--)
@@ -1425,12 +1460,13 @@ Thread::QueueThreadPlanForStepOverRange
bool abort_other_plans,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_other_threads
+ lldb::RunMode stop_other_threads,
+ LazyBool step_out_avoids_code_withoug_debug_info
)
{
ThreadPlanSP thread_plan_sp;
- thread_plan_sp.reset (new ThreadPlanStepOverRange (*this, range, addr_context, stop_other_threads));
-
+ thread_plan_sp.reset (new ThreadPlanStepOverRange (*this, range, addr_context, stop_other_threads, step_out_avoids_code_withoug_debug_info));
+
QueueThreadPlan (thread_plan_sp, abort_other_plans);
return thread_plan_sp;
}
@@ -1443,17 +1479,21 @@ Thread::QueueThreadPlanForStepInRange
const SymbolContext &addr_context,
const char *step_in_target,
lldb::RunMode stop_other_threads,
- bool avoid_code_without_debug_info
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info
)
{
ThreadPlanSP thread_plan_sp;
- ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this, range, addr_context, stop_other_threads);
- if (avoid_code_without_debug_info)
- plan->GetFlags().Set (ThreadPlanShouldStopHere::eAvoidNoDebug);
- else
- plan->GetFlags().Clear (ThreadPlanShouldStopHere::eAvoidNoDebug);
+ ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this,
+ range,
+ addr_context,
+ stop_other_threads,
+ step_in_avoids_code_without_debug_info,
+ step_out_avoids_code_without_debug_info);
+
if (step_in_target)
plan->SetStepInTarget(step_in_target);
+
thread_plan_sp.reset (plan);
QueueThreadPlan (thread_plan_sp, abort_other_plans);
@@ -1470,7 +1510,8 @@ Thread::QueueThreadPlanForStepOut
bool stop_other_threads,
Vote stop_vote,
Vote run_vote,
- uint32_t frame_idx
+ uint32_t frame_idx,
+ LazyBool step_out_avoids_code_withoug_debug_info
)
{
ThreadPlanSP thread_plan_sp (new ThreadPlanStepOut (*this,
@@ -1479,7 +1520,42 @@ Thread::QueueThreadPlanForStepOut
stop_other_threads,
stop_vote,
run_vote,
- frame_idx));
+ frame_idx,
+ step_out_avoids_code_withoug_debug_info));
+
+ if (thread_plan_sp->ValidatePlan(NULL))
+ {
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp;
+ }
+ else
+ {
+ return ThreadPlanSP();
+ }
+}
+
+ThreadPlanSP
+Thread::QueueThreadPlanForStepOutNoShouldStop
+(
+ bool abort_other_plans,
+ SymbolContext *addr_context,
+ bool first_insn,
+ bool stop_other_threads,
+ Vote stop_vote,
+ Vote run_vote,
+ uint32_t frame_idx
+)
+{
+ ThreadPlanStepOut *new_plan = new ThreadPlanStepOut (*this,
+ addr_context,
+ first_insn,
+ stop_other_threads,
+ stop_vote,
+ run_vote,
+ frame_idx,
+ eLazyBoolNo);
+ new_plan->ClearShouldStopHereCallbacks();
+ ThreadPlanSP thread_plan_sp(new_plan);
if (thread_plan_sp->ValidatePlan(NULL))
{
@@ -1651,6 +1727,9 @@ Thread::ClearStackFrames ()
if (m_curr_frames_sp && m_curr_frames_sp->GetAllFramesFetched())
m_prev_frames_sp.swap (m_curr_frames_sp);
m_curr_frames_sp.reset();
+
+ m_extended_info.reset();
+ m_extended_info_fetched = false;
}
lldb::StackFrameSP
@@ -1896,6 +1975,21 @@ Thread::GetThreadLocalData (const ModuleSP module)
return LLDB_INVALID_ADDRESS;
}
+bool
+Thread::SafeToCallFunctions ()
+{
+ Process *process = GetProcess().get();
+ if (process)
+ {
+ SystemRuntime *runtime = process->GetSystemRuntime ();
+ if (runtime)
+ {
+ return runtime->SafeToCallFunctionsOnThisThread (shared_from_this());
+ }
+ }
+ return true;
+}
+
lldb::StackFrameSP
Thread::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr)
{
@@ -1995,6 +2089,82 @@ Thread::GetStatus (Stream &strm, uint32_t start_frame, uint32_t num_frames, uint
return num_frames_shown;
}
+bool
+Thread::GetDescription (Stream &strm, lldb::DescriptionLevel level, bool print_json)
+{
+ DumpUsingSettingsFormat (strm, 0);
+ strm.Printf("\n");
+
+ StructuredData::ObjectSP thread_info = GetExtendedInfo();
+
+ if (thread_info && print_json)
+ {
+ thread_info->Dump (strm);
+ strm.Printf("\n");
+ return true;
+ }
+
+ if (thread_info)
+ {
+ StructuredData::ObjectSP activity = thread_info->GetObjectForDotSeparatedPath("activity");
+ StructuredData::ObjectSP breadcrumb = thread_info->GetObjectForDotSeparatedPath("breadcrumb");
+ StructuredData::ObjectSP messages = thread_info->GetObjectForDotSeparatedPath("trace_messages");
+
+ bool printed_activity = false;
+ if (activity && activity->GetType() == StructuredData::Type::eTypeDictionary)
+ {
+ StructuredData::Dictionary *activity_dict = activity->GetAsDictionary();
+ StructuredData::ObjectSP id = activity_dict->GetValueForKey("id");
+ StructuredData::ObjectSP name = activity_dict->GetValueForKey("name");
+ if (name && name->GetType() == StructuredData::Type::eTypeString
+ && id && id->GetType() == StructuredData::Type::eTypeInteger)
+ {
+ strm.Printf(" Activity '%s', 0x%" PRIx64 "\n", name->GetAsString()->GetValue().c_str(), id->GetAsInteger()->GetValue());
+ }
+ printed_activity = true;
+ }
+ bool printed_breadcrumb = false;
+ if (breadcrumb && breadcrumb->GetType() == StructuredData::Type::eTypeDictionary)
+ {
+ if (printed_activity)
+ strm.Printf ("\n");
+ StructuredData::Dictionary *breadcrumb_dict = breadcrumb->GetAsDictionary();
+ StructuredData::ObjectSP breadcrumb_text = breadcrumb_dict->GetValueForKey ("name");
+ if (breadcrumb_text && breadcrumb_text->GetType() == StructuredData::Type::eTypeString)
+ {
+ strm.Printf (" Current Breadcrumb: %s\n", breadcrumb_text->GetAsString()->GetValue().c_str());
+ }
+ printed_breadcrumb = true;
+ }
+ if (messages && messages->GetType() == StructuredData::Type::eTypeArray)
+ {
+ if (printed_breadcrumb)
+ strm.Printf("\n");
+ StructuredData::Array *messages_array = messages->GetAsArray();
+ const size_t msg_count = messages_array->GetSize();
+ if (msg_count > 0)
+ {
+ strm.Printf (" %zu trace messages:\n", msg_count);
+ for (size_t i = 0; i < msg_count; i++)
+ {
+ StructuredData::ObjectSP message = messages_array->GetItemAtIndex(i);
+ if (message && message->GetType() == StructuredData::Type::eTypeDictionary)
+ {
+ StructuredData::Dictionary *message_dict = message->GetAsDictionary();
+ StructuredData::ObjectSP message_text = message_dict->GetValueForKey ("message");
+ if (message_text && message_text->GetType() == StructuredData::Type::eTypeString)
+ {
+ strm.Printf (" %s\n", message_text->GetAsString()->GetValue().c_str());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
size_t
Thread::GetStackFrameStatus (Stream& strm,
uint32_t first_frame,
@@ -2021,6 +2191,7 @@ Thread::GetUnwinder ()
case llvm::Triple::x86_64:
case llvm::Triple::x86:
case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
case llvm::Triple::thumb:
case llvm::Triple::mips64:
case llvm::Triple::hexagon:
@@ -2059,7 +2230,8 @@ Thread::IsStillAtLastBreakpointHit ()
{
lldb::addr_t pc = reg_ctx_sp->GetPC();
BreakpointSiteSP bp_site_sp = GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
- if (bp_site_sp && value == bp_site_sp->GetID())
+ if (bp_site_sp &&
+ static_cast<break_id_t>(value) == bp_site_sp->GetID())
return true;
}
}
@@ -2070,8 +2242,9 @@ Thread::IsStillAtLastBreakpointHit ()
Error
Thread::StepIn (bool source_step,
- bool avoid_code_without_debug_info)
-
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info)
+
{
Error error;
Process *process = GetProcess().get();
@@ -2090,7 +2263,8 @@ Thread::StepIn (bool source_step,
sc,
NULL,
run_mode,
- avoid_code_without_debug_info);
+ step_in_avoids_code_without_debug_info,
+ step_out_avoids_code_without_debug_info);
}
else
{
@@ -2114,8 +2288,8 @@ Thread::StepIn (bool source_step,
}
Error
-Thread::StepOver (bool source_step)
-
+Thread::StepOver (bool source_step,
+ LazyBool step_out_avoids_code_without_debug_info)
{
Error error;
Process *process = GetProcess().get();
@@ -2133,7 +2307,8 @@ Thread::StepOver (bool source_step)
new_plan_sp = QueueThreadPlanForStepOverRange (abort_other_plans,
sc.line_entry.range,
sc,
- run_mode);
+ run_mode,
+ step_out_avoids_code_without_debug_info);
}
else
{
@@ -2187,4 +2362,4 @@ Thread::StepOut ()
error.SetErrorString("process not stopped");
}
return error;
-} \ No newline at end of file
+}
diff --git a/source/Target/ThreadList.cpp b/source/Target/ThreadList.cpp
index 4fffdac9a34e..7fb16fdac5c0 100644
--- a/source/Target/ThreadList.cpp
+++ b/source/Target/ThreadList.cpp
@@ -262,7 +262,7 @@ ThreadList::ShouldStop (Event *event_ptr)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
// The ShouldStop method of the threads can do a whole lot of work,
- // running breakpoint commands & conditions, etc. So we don't want
+ // figuring out whether the thread plan conditions are met. So we don't want
// to keep the ThreadList locked the whole time we are doing this.
// FIXME: It is possible that running code could cause new threads
// to be created. If that happens we will miss asking them whether
@@ -287,7 +287,16 @@ ThreadList::ShouldStop (Event *event_ptr)
}
bool did_anybody_stop_for_a_reason = false;
+
+ // If the event is an Interrupt event, then we're going to stop no matter what. Otherwise, presume we won't stop.
bool should_stop = false;
+ if (Process::ProcessEventData::GetInterruptedFromEvent(event_ptr))
+ {
+ if (log)
+ log->Printf("ThreadList::%s handling interrupt event, should stop set to true", __FUNCTION__);
+
+ should_stop = true;
+ }
// Now we run through all the threads and get their stop info's. We want to make sure to do this first before
// we start running the ShouldStop, because one thread's ShouldStop could destroy information (like deleting a
diff --git a/source/Target/ThreadPlan.cpp b/source/Target/ThreadPlan.cpp
index 65d51bd01734..2c9b7fce7c24 100644
--- a/source/Target/ThreadPlan.cpp
+++ b/source/Target/ThreadPlan.cpp
@@ -161,16 +161,11 @@ ThreadPlan::WillResume (StateType resume_state, bool current_plan)
addr_t fp = reg_ctx->GetFP();
log->Printf("%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", "
"plan = '%s', state = %s, stop others = %d",
- __FUNCTION__,
- m_thread.GetIndexID(),
- &m_thread,
- m_thread.GetID(),
- (uint64_t)pc,
- (uint64_t)sp,
- (uint64_t)fp,
- m_name.c_str(),
- StateAsCString(resume_state),
- StopOthers());
+ __FUNCTION__, m_thread.GetIndexID(),
+ static_cast<void*>(&m_thread), m_thread.GetID(),
+ static_cast<uint64_t>(pc), static_cast<uint64_t>(sp),
+ static_cast<uint64_t>(fp), m_name.c_str(),
+ StateAsCString(resume_state), StopOthers());
}
}
return DoWillResume (resume_state, current_plan);
diff --git a/source/Target/ThreadPlanBase.cpp b/source/Target/ThreadPlanBase.cpp
index 240f23a0b8f4..d70afae55573 100644
--- a/source/Target/ThreadPlanBase.cpp
+++ b/source/Target/ThreadPlanBase.cpp
@@ -151,7 +151,7 @@ ThreadPlanBase::ShouldStop (Event *event_ptr)
// If we crashed, discard thread plans and stop. Don't force the discard, however,
// since on rerun the target may clean up this exception and continue normally from there.
if (log)
- log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (exception.)", m_thread.GetID());
+ log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (exception: %s)", m_thread.GetID(), stop_info_sp->GetDescription());
m_thread.DiscardThreadPlans(false);
return true;
@@ -168,7 +168,7 @@ ThreadPlanBase::ShouldStop (Event *event_ptr)
if (stop_info_sp->ShouldStop(event_ptr))
{
if (log)
- log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (signal.)", m_thread.GetID());
+ log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (signal: %s)", m_thread.GetID(), stop_info_sp->GetDescription());
m_thread.DiscardThreadPlans(false);
return true;
}
diff --git a/source/Target/ThreadPlanCallFunction.cpp b/source/Target/ThreadPlanCallFunction.cpp
index 854750b85817..5a3ebd7b1284 100644
--- a/source/Target/ThreadPlanCallFunction.cpp
+++ b/source/Target/ThreadPlanCallFunction.cpp
@@ -12,7 +12,7 @@
// C Includes
// C++ Includes
// Other libraries and framework includes
-#include "llvm/Support/MachO.h"
+
// Project includes
#include "lldb/lldb-private-log.h"
#include "lldb/Breakpoint/Breakpoint.h"
@@ -49,16 +49,16 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
ProcessSP process_sp (thread.GetProcess());
if (!process_sp)
return false;
-
+
abi = process_sp->GetABI().get();
-
+
if (!abi)
return false;
-
+
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP));
-
+
SetBreakpoints();
-
+
m_function_sp = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
// If we can't read memory at the point of the process where we are planning to put our function, we're
// not going to get any further...
@@ -68,17 +68,21 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
{
m_constructor_errors.Printf ("Trying to put the stack in unreadable memory at: 0x%" PRIx64 ".", m_function_sp);
if (log)
- log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
+ log->Printf ("ThreadPlanCallFunction(%p): %s.",
+ static_cast<void*>(this),
+ m_constructor_errors.GetData());
return false;
}
-
+
Module *exe_module = GetTarget().GetExecutableModulePointer();
if (exe_module == NULL)
{
m_constructor_errors.Printf ("Can't execute code without an executable module.");
if (log)
- log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
+ log->Printf ("ThreadPlanCallFunction(%p): %s.",
+ static_cast<void*>(this),
+ m_constructor_errors.GetData());
return false;
}
else
@@ -90,23 +94,27 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
exe_module->GetFileSpec().GetFilename().AsCString());
if (log)
- log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
+ log->Printf ("ThreadPlanCallFunction(%p): %s.",
+ static_cast<void*>(this),
+ m_constructor_errors.GetData());
return false;
}
-
+
m_start_addr = objectFile->GetEntryPointAddress();
if (!m_start_addr.IsValid())
{
m_constructor_errors.Printf ("Could not find entry point address for executable module \"%s\".",
exe_module->GetFileSpec().GetFilename().AsCString());
if (log)
- log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
+ log->Printf ("ThreadPlanCallFunction(%p): %s.",
+ static_cast<void*>(this),
+ m_constructor_errors.GetData());
return false;
}
}
-
+
start_load_addr = m_start_addr.GetLoadAddress (&GetTarget());
-
+
// Checkpoint the thread state so we can restore it later.
if (log && log->GetVerbose())
ReportRegisterState ("About to checkpoint thread before function call. Original register state was:");
@@ -115,11 +123,13 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
{
m_constructor_errors.Printf ("Setting up ThreadPlanCallFunction, failed to checkpoint thread state.");
if (log)
- log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
+ log->Printf ("ThreadPlanCallFunction(%p): %s.",
+ static_cast<void*>(this),
+ m_constructor_errors.GetData());
return false;
}
function_load_addr = m_function_addr.GetLoadAddress (&GetTarget());
-
+
return true;
}
@@ -148,16 +158,16 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
lldb::addr_t function_load_addr;
if (!ConstructorSetup (thread, abi, start_load_addr, function_load_addr))
return;
-
+
if (!abi->PrepareTrivialCall(thread,
m_function_sp,
function_load_addr,
start_load_addr,
args))
return;
-
+
ReportRegisterState ("Function call was set up. Register state was:");
-
+
m_valid = true;
}
@@ -198,15 +208,16 @@ void
ThreadPlanCallFunction::DoTakedown (bool success)
{
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP));
-
+
if (!m_valid)
{
//Don't call DoTakedown if we were never valid to begin with.
if (log)
- log->Printf ("ThreadPlanCallFunction(%p): Log called on ThreadPlanCallFunction that was never valid.", this);
+ log->Printf ("ThreadPlanCallFunction(%p): Log called on ThreadPlanCallFunction that was never valid.",
+ static_cast<void*>(this));
return;
}
-
+
if (!m_takedown_done)
{
if (success)
@@ -220,14 +231,17 @@ ThreadPlanCallFunction::DoTakedown (bool success)
}
}
if (log)
- log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", this, m_thread.GetID(), m_valid, IsPlanComplete());
+ log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n",
+ static_cast<void*>(this), m_thread.GetID(), m_valid,
+ IsPlanComplete());
m_takedown_done = true;
m_stop_address = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
m_real_stop_info_sp = GetPrivateStopInfo ();
if (!m_thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state))
{
if (log)
- log->Printf("ThreadPlanCallFunction(%p): DoTakedown failed to restore register state", this);
+ log->Printf("ThreadPlanCallFunction(%p): DoTakedown failed to restore register state",
+ static_cast<void*>(this));
}
SetPlanComplete(success);
ClearBreakpoints();
@@ -238,7 +252,9 @@ ThreadPlanCallFunction::DoTakedown (bool success)
else
{
if (log)
- log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called as no-op for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", this, m_thread.GetID(), m_valid, IsPlanComplete());
+ log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called as no-op for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n",
+ static_cast<void*>(this), m_thread.GetID(), m_valid,
+ IsPlanComplete());
}
}
@@ -317,6 +333,14 @@ ThreadPlanCallFunction::DoPlanExplainsStop (Event *event_ptr)
if (stop_reason == eStopReasonBreakpoint && BreakpointsExplainStop())
return true;
+ // One more quirk here. If this event was from Halt interrupting the target, then we should not consider
+ // ourselves complete. Return true to acknowledge the stop.
+ if (Process::ProcessEventData::GetInterruptedFromEvent(event_ptr))
+ {
+ if (log)
+ log->Printf ("ThreadPlanCallFunction::PlanExplainsStop: The event is an Interrupt, returning true.");
+ return true;
+ }
// We control breakpoints separately from other "stop reasons." So first,
// check the case where we stopped for an internal breakpoint, in that case, continue on.
// If it is not an internal breakpoint, consult m_ignore_breakpoints.
@@ -425,17 +449,6 @@ ThreadPlanCallFunction::StopOthers ()
return m_stop_other_threads;
}
-void
-ThreadPlanCallFunction::SetStopOthers (bool new_value)
-{
- if (m_subplan_sp)
- {
- ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get());
- address_plan->SetStopOthers(new_value);
- }
- m_stop_other_threads = new_value;
-}
-
StateType
ThreadPlanCallFunction::GetPlanRunState ()
{
@@ -470,11 +483,12 @@ bool
ThreadPlanCallFunction::MischiefManaged ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
-
+
if (IsPlanComplete())
{
if (log)
- log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.", this);
+ log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.",
+ static_cast<void*>(this));
ThreadPlan::MischiefManaged ();
return true;
@@ -547,6 +561,13 @@ ThreadPlanCallFunction::BreakpointsExplainStop()
return false;
}
+void
+ThreadPlanCallFunction::SetStopOthers (bool new_value)
+{
+ m_subplan_sp->SetStopOthers(new_value);
+}
+
+
bool
ThreadPlanCallFunction::RestoreThreadState()
{
diff --git a/source/Target/ThreadPlanCallUserExpression.cpp b/source/Target/ThreadPlanCallUserExpression.cpp
index 827de3e6057a..90b8cf81171f 100644
--- a/source/Target/ThreadPlanCallUserExpression.cpp
+++ b/source/Target/ThreadPlanCallUserExpression.cpp
@@ -12,7 +12,7 @@
// C Includes
// C++ Includes
// Other libraries and framework includes
-#include "llvm/Support/MachO.h"
+
// Project includes
#include "lldb/lldb-private-log.h"
#include "lldb/Breakpoint/Breakpoint.h"
@@ -21,6 +21,7 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -56,7 +57,54 @@ ThreadPlanCallUserExpression::~ThreadPlanCallUserExpression ()
void
ThreadPlanCallUserExpression::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
- ThreadPlanCallFunction::GetDescription (s, level);
+ if (level == eDescriptionLevelBrief)
+ s->Printf("User Expression thread plan");
+ else
+ ThreadPlanCallFunction::GetDescription (s, level);
+}
+
+void
+ThreadPlanCallUserExpression::WillPop ()
+{
+ ThreadPlanCallFunction::WillPop();
+ if (m_user_expression_sp)
+ m_user_expression_sp.reset();
+}
+
+bool
+ThreadPlanCallUserExpression::MischiefManaged ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (IsPlanComplete())
+ {
+ if (log)
+ log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.",
+ static_cast<void*>(this));
+
+ if (m_manage_materialization && PlanSucceeded() && m_user_expression_sp)
+ {
+ lldb::addr_t function_stack_top;
+ lldb::addr_t function_stack_bottom;
+ lldb::addr_t function_stack_pointer = GetFunctionStackPointer();
+
+ function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize();
+ function_stack_top = function_stack_pointer;
+
+ StreamString error_stream;
+
+ ExecutionContext exe_ctx(GetThread());
+
+ m_user_expression_sp->FinalizeJITExecution(error_stream, exe_ctx, m_result_var_sp, function_stack_bottom, function_stack_top);
+ }
+
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
}
StopInfoSP
diff --git a/source/Target/ThreadPlanRunToAddress.cpp b/source/Target/ThreadPlanRunToAddress.cpp
index 9e7713973054..e2f85c0c5f5f 100644
--- a/source/Target/ThreadPlanRunToAddress.cpp
+++ b/source/Target/ThreadPlanRunToAddress.cpp
@@ -69,7 +69,7 @@ ThreadPlanRunToAddress::ThreadPlanRunToAddress
m_addresses (addresses),
m_break_ids ()
{
- // Convert all addressses into opcode addresses to make sure we set
+ // Convert all addresses into opcode addresses to make sure we set
// breakpoints at the correct address.
Target &target = thread.GetProcess()->GetTarget();
std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end();
diff --git a/source/Target/ThreadPlanShouldStopHere.cpp b/source/Target/ThreadPlanShouldStopHere.cpp
index 87662345a06d..e89f5d2bde1b 100644
--- a/source/Target/ThreadPlanShouldStopHere.cpp
+++ b/source/Target/ThreadPlanShouldStopHere.cpp
@@ -23,12 +23,23 @@ using namespace lldb_private;
//----------------------------------------------------------------------
// ThreadPlanShouldStopHere constructor
//----------------------------------------------------------------------
-ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner, ThreadPlanShouldStopHereCallback callback, void *baton) :
- m_callback (callback),
- m_baton (baton),
+ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner) :
+ m_callbacks (),
+ m_baton (NULL),
m_owner (owner),
m_flags (ThreadPlanShouldStopHere::eNone)
{
+ m_callbacks.should_stop_here_callback = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback;
+ m_callbacks.step_from_here_callback = ThreadPlanShouldStopHere::DefaultStepFromHereCallback;
+}
+
+ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner, const ThreadPlanShouldStopHereCallbacks *callbacks, void *baton) :
+ m_callbacks (),
+ m_baton (),
+ m_owner (owner),
+ m_flags (ThreadPlanShouldStopHere::eNone)
+{
+ SetShouldStopHereCallbacks(callbacks, baton);
}
//----------------------------------------------------------------------
@@ -38,37 +49,120 @@ ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere()
{
}
-void
-ThreadPlanShouldStopHere::SetShouldStopHereCallback (ThreadPlanShouldStopHereCallback callback, void *baton)
+bool
+ThreadPlanShouldStopHere::InvokeShouldStopHereCallback (FrameComparison operation)
{
- m_callback = callback;
- m_baton = baton;
-}
-
-ThreadPlanSP
-ThreadPlanShouldStopHere::InvokeShouldStopHereCallback ()
-{
- if (m_callback)
+ bool should_stop_here = true;
+ if (m_callbacks.should_stop_here_callback)
{
- ThreadPlanSP return_plan_sp(m_callback (m_owner, m_flags, m_baton));
+ should_stop_here = m_callbacks.should_stop_here_callback (m_owner, m_flags, operation, m_baton);
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (log)
{
lldb::addr_t current_addr = m_owner->GetThread().GetRegisterContext()->GetPC(0);
- if (return_plan_sp)
- {
- StreamString s;
- return_plan_sp->GetDescription (&s, lldb::eDescriptionLevelFull);
- log->Printf ("ShouldStopHere callback found a step out plan from 0x%" PRIx64 ": %s.", current_addr, s.GetData());
- }
- else
- {
- log->Printf ("ShouldStopHere callback didn't find a step out plan from: 0x%" PRIx64 ".", current_addr);
- }
+ log->Printf ("ShouldStopHere callback returned %u from 0x%" PRIx64 ".", should_stop_here, current_addr);
}
+ }
+
+ return should_stop_here;
+}
+
+bool
+ThreadPlanShouldStopHere::DefaultShouldStopHereCallback (ThreadPlan *current_plan,
+ Flags &flags,
+ FrameComparison operation,
+ void *baton)
+{
+ bool should_stop_here = true;
+ StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
+ if (!frame)
+ return true;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug))
+ || (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug))
+ || (operation == eFrameCompareSameParent && flags.Test(eStepInAvoidNoDebug)))
+ {
+ if (!frame->HasDebugInformation())
+ {
+ if (log)
+ log->Printf ("Stepping out of frame with no debug info");
+
+ should_stop_here = false;
+ }
+ }
+
+ // Always avoid code with line number 0.
+ // FIXME: At present the ShouldStop and the StepFromHere calculate this independently. If this ever
+ // becomes expensive (this one isn't) we can try to have this set a state that the StepFromHere can use.
+ if (frame)
+ {
+ SymbolContext sc;
+ sc = frame->GetSymbolContext (eSymbolContextLineEntry);
+ if (sc.line_entry.line == 0)
+ should_stop_here = false;
+ }
+
+ return should_stop_here;
+}
+
+ThreadPlanSP
+ThreadPlanShouldStopHere::DefaultStepFromHereCallback (ThreadPlan *current_plan,
+ Flags &flags,
+ FrameComparison operation,
+ void *baton)
+{
+ const bool stop_others = false;
+ const size_t frame_index = 0;
+ ThreadPlanSP return_plan_sp;
+ // If we are stepping through code at line number 0, then we need to step over this range. Otherwise
+ // we will step out.
+ StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
+ if (!frame)
return return_plan_sp;
+ SymbolContext sc;
+ sc = frame->GetSymbolContext (eSymbolContextLineEntry);
+ if (sc.line_entry.line == 0)
+ {
+ AddressRange range = sc.line_entry.range;
+ return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOverRange(false,
+ range,
+ sc,
+ eOnlyDuringStepping,
+ eLazyBoolNo);
+ }
+
+ if (!return_plan_sp)
+ return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop (false,
+ NULL,
+ true,
+ stop_others,
+ eVoteNo,
+ eVoteNoOpinion,
+ frame_index);
+ return return_plan_sp;
+}
+
+ThreadPlanSP
+ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(lldb_private::Flags &flags, lldb::FrameComparison operation)
+{
+ ThreadPlanSP return_plan_sp;
+ if (m_callbacks.step_from_here_callback)
+ {
+ return_plan_sp = m_callbacks.step_from_here_callback (m_owner, flags, operation, m_baton);
}
+ return return_plan_sp;
+
+}
+
+lldb::ThreadPlanSP
+ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut (lldb::FrameComparison operation)
+{
+ if (!InvokeShouldStopHereCallback(operation))
+ return QueueStepOutFromHerePlan(m_flags, operation);
else
return ThreadPlanSP();
}
+
diff --git a/source/Target/ThreadPlanStepInRange.cpp b/source/Target/ThreadPlanStepInRange.cpp
index c4cb9aba1b3e..3e9abef65573 100644
--- a/source/Target/ThreadPlanStepInRange.cpp
+++ b/source/Target/ThreadPlanStepInRange.cpp
@@ -31,7 +31,7 @@
using namespace lldb;
using namespace lldb_private;
-uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug;
+uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eStepInAvoidNoDebug;
//----------------------------------------------------------------------
// ThreadPlanStepInRange: Step through a stack range, either stepping over or into
@@ -43,14 +43,18 @@ ThreadPlanStepInRange::ThreadPlanStepInRange
Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others
+ lldb::RunMode stop_others,
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info
) :
ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
- ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
+ ThreadPlanShouldStopHere (this),
m_step_past_prologue (true),
m_virtual_step (false)
{
+ SetCallbacks();
SetFlagsToDefault ();
+ SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info);
}
ThreadPlanStepInRange::ThreadPlanStepInRange
@@ -59,15 +63,19 @@ ThreadPlanStepInRange::ThreadPlanStepInRange
const AddressRange &range,
const SymbolContext &addr_context,
const char *step_into_target,
- lldb::RunMode stop_others
+ lldb::RunMode stop_others,
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info
) :
ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
- ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
+ ThreadPlanShouldStopHere (this),
m_step_past_prologue (true),
m_virtual_step (false),
m_step_into_target (step_into_target)
{
+ SetCallbacks();
SetFlagsToDefault ();
+ SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info);
}
ThreadPlanStepInRange::~ThreadPlanStepInRange ()
@@ -75,6 +83,48 @@ ThreadPlanStepInRange::~ThreadPlanStepInRange ()
}
void
+ThreadPlanStepInRange::SetupAvoidNoDebug(LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info)
+{
+ bool avoid_nodebug = true;
+
+ switch (step_in_avoids_code_without_debug_info)
+ {
+ case eLazyBoolYes:
+ avoid_nodebug = true;
+ break;
+ case eLazyBoolNo:
+ avoid_nodebug = false;
+ break;
+ case eLazyBoolCalculate:
+ avoid_nodebug = m_thread.GetStepInAvoidsNoDebug();
+ break;
+ }
+ if (avoid_nodebug)
+ GetFlags().Set (ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
+ else
+ GetFlags().Clear (ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
+
+ avoid_nodebug = true;
+ switch (step_out_avoids_code_without_debug_info)
+ {
+ case eLazyBoolYes:
+ avoid_nodebug = true;
+ break;
+ case eLazyBoolNo:
+ avoid_nodebug = false;
+ break;
+ case eLazyBoolCalculate:
+ avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
+ break;
+ }
+ if (avoid_nodebug)
+ GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
+ else
+ GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
+}
+
+void
ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
@@ -124,7 +174,8 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
{
// If we've just completed a virtual step, all we need to do is check for a ShouldStopHere plan, and otherwise
// we're done.
- m_sub_plan_sp = InvokeShouldStopHereCallback();
+ // FIXME - This can be both a step in and a step out. Probably should record which in the m_virtual_step.
+ m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger);
}
else
{
@@ -139,7 +190,7 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
FrameComparison frame_order = CompareCurrentFrameToStartFrame();
- if (frame_order == eFrameCompareOlder)
+ if (frame_order == eFrameCompareOlder || frame_order == eFrameCompareSameParent)
{
// If we're in an older frame then we should stop.
//
@@ -148,7 +199,12 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
// in a trampoline we think the frame is older because the trampoline confused the backtracer.
m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
if (!m_sub_plan_sp)
- return true;
+ {
+ // Otherwise check the ShouldStopHere for step out:
+ m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
+ if (log)
+ log->Printf ("ShouldStopHere says we should step out of this frame.");
+ }
else if (log)
{
log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
@@ -196,7 +252,7 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
// If not, give the "should_stop" callback a chance to push a plan to get us out of here.
// But only do that if we actually have stepped in.
if (!m_sub_plan_sp && frame_order == eFrameCompareYounger)
- m_sub_plan_sp = InvokeShouldStopHereCallback();
+ m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);
// If we've stepped in and we are going to stop here, check to see if we were asked to
// run past the prologue, and if so do that.
@@ -251,12 +307,6 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
}
}
-void
-ThreadPlanStepInRange::SetFlagsToDefault ()
-{
- GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
-}
-
void
ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
{
@@ -344,25 +394,19 @@ ThreadPlanStepInRange::FrameMatchesAvoidCriteria ()
return false;
}
-ThreadPlanSP
-ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
+bool
+ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, FrameComparison operation, void *baton)
{
- bool should_step_out = false;
+ bool should_stop_here = true;
StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
- if (flags.Test(eAvoidNoDebug))
- {
- if (!frame->HasDebugInformation())
- {
- if (log)
- log->Printf ("Stepping out of frame with no debug info");
-
- should_step_out = true;
- }
- }
+ // First see if the ThreadPlanShouldStopHere default implementation thinks we should get out of here:
+ should_stop_here = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback (current_plan, flags, operation, baton);
+ if (!should_stop_here)
+ return should_stop_here;
- if (current_plan->GetKind() == eKindStepInRange)
+ if (should_stop_here && current_plan->GetKind() == eKindStepInRange && operation == eFrameCompareYounger)
{
ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
if (step_in_range_plan->m_step_into_target)
@@ -373,7 +417,7 @@ ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan,
// First try an exact match, since that's cheap with ConstStrings. Then do a strstr compare.
if (step_in_range_plan->m_step_into_target == sc.GetFunctionName())
{
- should_step_out = false;
+ should_stop_here = true;
}
else
{
@@ -381,42 +425,26 @@ ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan,
const char *function_name = sc.GetFunctionName().AsCString();
if (function_name == NULL)
- should_step_out = true;
+ should_stop_here = false;
else if (strstr (function_name, target_name) == NULL)
- should_step_out = true;
+ should_stop_here = false;
}
- if (log && should_step_out)
+ if (log && !should_stop_here)
log->Printf("Stepping out of frame %s which did not match step into target %s.",
sc.GetFunctionName().AsCString(),
step_in_range_plan->m_step_into_target.AsCString());
}
}
- if (!should_step_out)
+ if (should_stop_here)
{
ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
// Don't log the should_step_out here, it's easier to do it in FrameMatchesAvoidCriteria.
- should_step_out = step_in_range_plan->FrameMatchesAvoidCriteria ();
+ should_stop_here = !step_in_range_plan->FrameMatchesAvoidCriteria ();
}
}
-
- if (should_step_out)
- {
- // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
- // We really should have all plans take the tri-state for "stop others" so we can do the right
- // thing. For now let's be safe and always run others when we are likely to run arbitrary code.
- const bool stop_others = false;
- return current_plan->GetThread().QueueThreadPlanForStepOut (false,
- NULL,
- true,
- stop_others,
- eVoteNo,
- eVoteNoOpinion,
- 0); // Frame index
- }
-
- return ThreadPlanSP();
+ return should_stop_here;
}
bool
diff --git a/source/Target/ThreadPlanStepInstruction.cpp b/source/Target/ThreadPlanStepInstruction.cpp
index f644ee88f701..fabf63b1e9d6 100644
--- a/source/Target/ThreadPlanStepInstruction.cpp
+++ b/source/Target/ThreadPlanStepInstruction.cpp
@@ -43,21 +43,28 @@ ThreadPlanStepInstruction::ThreadPlanStepInstruction
m_stop_other_threads (stop_other_threads),
m_step_over (step_over)
{
+ m_takes_iteration_count = true;
+ SetUpState();
+}
+
+ThreadPlanStepInstruction::~ThreadPlanStepInstruction ()
+{
+}
+
+void
+ThreadPlanStepInstruction::SetUpState()
+{
m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
- StackFrameSP m_start_frame_sp(m_thread.GetStackFrameAtIndex(0));
- m_stack_id = m_start_frame_sp->GetStackID();
+ StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0));
+ m_stack_id = start_frame_sp->GetStackID();
- m_start_has_symbol = m_start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != NULL;
+ m_start_has_symbol = start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != NULL;
StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1);
if (parent_frame_sp)
m_parent_frame_id = parent_frame_sp->GetStackID();
}
-ThreadPlanStepInstruction::~ThreadPlanStepInstruction ()
-{
-}
-
void
ThreadPlanStepInstruction::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
@@ -106,6 +113,37 @@ ThreadPlanStepInstruction::DoPlanExplainsStop (Event *event_ptr)
}
bool
+ThreadPlanStepInstruction::IsPlanStale ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+ if (cur_frame_id == m_stack_id)
+ {
+ if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
+ return true;
+ else
+ return false;
+ }
+ else if (cur_frame_id < m_stack_id)
+ {
+ // If the current frame is younger than the start frame and we are stepping over, then we need to continue,
+ // but if we are doing just one step, we're done.
+ if (m_step_over)
+ return false;
+ else
+ return true;
+ }
+ else
+ {
+ if (log)
+ {
+ log->Printf ("ThreadPlanStepInstruction::IsPlanStale - Current frame is older than start frame, plan is stale.");
+ }
+ return true;
+ }
+}
+
+bool
ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
{
if (m_step_over)
@@ -118,8 +156,18 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
{
if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
{
- SetPlanComplete();
- return true;
+ if (--m_iteration_count <= 0)
+ {
+ SetPlanComplete();
+ return true;
+ }
+ else
+ {
+ // We are still stepping, reset the start pc, and in case we've stepped out,
+ // reset the current stack id.
+ SetUpState();
+ return false;
+ }
}
else
return false;
@@ -147,13 +195,13 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
// StepInstruction should probably have the tri-state RunMode, but for now it is safer to
// run others.
const bool stop_others = false;
- m_thread.QueueThreadPlanForStepOut(false,
- NULL,
- true,
- stop_others,
- eVoteNo,
- eVoteNoOpinion,
- 0);
+ m_thread.QueueThreadPlanForStepOutNoShouldStop(false,
+ NULL,
+ true,
+ stop_others,
+ eVoteNo,
+ eVoteNoOpinion,
+ 0);
return false;
}
else
@@ -182,8 +230,18 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
{
if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
{
- SetPlanComplete();
- return true;
+ if (--m_iteration_count <= 0)
+ {
+ SetPlanComplete();
+ return true;
+ }
+ else
+ {
+ // We are still stepping, reset the start pc, and in case we've stepped in or out,
+ // reset the current stack id.
+ SetUpState();
+ return false;
+ }
}
else
return false;
diff --git a/source/Target/ThreadPlanStepOut.cpp b/source/Target/ThreadPlanStepOut.cpp
index c5efb5581527..b62f557319a8 100644
--- a/source/Target/ThreadPlanStepOut.cpp
+++ b/source/Target/ThreadPlanStepOut.cpp
@@ -26,10 +26,13 @@
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlanStepOverRange.h"
+#include "lldb/Target/ThreadPlanStepThrough.h"
using namespace lldb;
using namespace lldb_private;
+uint32_t ThreadPlanStepOut::s_default_flag_values = 0;
+
//----------------------------------------------------------------------
// ThreadPlanStepOut: Step out of the current frame
//----------------------------------------------------------------------
@@ -41,20 +44,21 @@ ThreadPlanStepOut::ThreadPlanStepOut
bool stop_others,
Vote stop_vote,
Vote run_vote,
- uint32_t frame_idx
+ uint32_t frame_idx,
+ LazyBool step_out_avoids_code_without_debug_info
) :
ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote),
- m_step_from_context (context),
+ ThreadPlanShouldStopHere (this),
m_step_from_insn (LLDB_INVALID_ADDRESS),
m_return_bp_id (LLDB_INVALID_BREAK_ID),
m_return_addr (LLDB_INVALID_ADDRESS),
- m_first_insn (first_insn),
m_stop_others (stop_others),
- m_step_through_inline_plan_sp(),
- m_step_out_plan_sp (),
m_immediate_step_from_function(NULL)
{
+ SetFlagsToDefault();
+ SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
+
m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
@@ -77,13 +81,15 @@ ThreadPlanStepOut::ThreadPlanStepOut
{
// First queue a plan that gets us to this inlined frame, and when we get there we'll queue a second
// plan that walks us out of this frame.
- m_step_out_plan_sp.reset (new ThreadPlanStepOut(m_thread,
+ m_step_out_to_inline_plan_sp.reset (new ThreadPlanStepOut(m_thread,
NULL,
false,
stop_others,
eVoteNoOpinion,
eVoteNoOpinion,
- frame_idx - 1));
+ frame_idx - 1,
+ eLazyBoolNo));
+ static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())->SetShouldStopHereCallbacks(nullptr, nullptr);
}
else
{
@@ -123,10 +129,32 @@ ThreadPlanStepOut::ThreadPlanStepOut
}
void
+ThreadPlanStepOut::SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)
+{
+ bool avoid_nodebug = true;
+ switch (step_out_avoids_code_without_debug_info)
+ {
+ case eLazyBoolYes:
+ avoid_nodebug = true;
+ break;
+ case eLazyBoolNo:
+ avoid_nodebug = false;
+ break;
+ case eLazyBoolCalculate:
+ avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
+ break;
+ }
+ if (avoid_nodebug)
+ GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
+ else
+ GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
+}
+
+void
ThreadPlanStepOut::DidPush()
{
- if (m_step_out_plan_sp)
- m_thread.QueueThreadPlan(m_step_out_plan_sp, false);
+ if (m_step_out_to_inline_plan_sp)
+ m_thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false);
else if (m_step_through_inline_plan_sp)
m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
}
@@ -144,7 +172,7 @@ ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
s->Printf ("step out");
else
{
- if (m_step_out_plan_sp)
+ if (m_step_out_to_inline_plan_sp)
s->Printf ("Stepping out to inlined frame so we can walk through it.");
else if (m_step_through_inline_plan_sp)
s->Printf ("Stepping out by stepping through inlined function.");
@@ -159,8 +187,8 @@ ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
bool
ThreadPlanStepOut::ValidatePlan (Stream *error)
{
- if (m_step_out_plan_sp)
- return m_step_out_plan_sp->ValidatePlan (error);
+ if (m_step_out_to_inline_plan_sp)
+ return m_step_out_to_inline_plan_sp->ValidatePlan (error);
else if (m_step_through_inline_plan_sp)
return m_step_through_inline_plan_sp->ValidatePlan (error);
else if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
@@ -176,12 +204,18 @@ ThreadPlanStepOut::ValidatePlan (Stream *error)
bool
ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)
{
- // If one of our child plans just finished, then we do explain the stop.
- if (m_step_out_plan_sp)
+ // If the step out plan is done, then we just need to step through the inlined frame.
+ if (m_step_out_to_inline_plan_sp)
{
- if (m_step_out_plan_sp->MischiefManaged())
+ if (m_step_out_to_inline_plan_sp->MischiefManaged())
+ return true;
+ else
+ return false;
+ }
+ else if (m_step_through_inline_plan_sp)
+ {
+ if (m_step_through_inline_plan_sp->MischiefManaged())
{
- // If this one is done, then we are all done.
CalculateReturnValue();
SetPlanComplete();
return true;
@@ -189,9 +223,9 @@ ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)
else
return false;
}
- else if (m_step_through_inline_plan_sp)
+ else if (m_step_out_further_plan_sp)
{
- if (m_step_through_inline_plan_sp->MischiefManaged())
+ if (m_step_out_further_plan_sp->MischiefManaged())
return true;
else
return false;
@@ -234,8 +268,11 @@ ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)
if (done)
{
- CalculateReturnValue();
- SetPlanComplete();
+ if (InvokeShouldStopHereCallback (eFrameCompareOlder))
+ {
+ CalculateReturnValue();
+ SetPlanComplete();
+ }
}
// If there was only one owner, then we're done. But if we also hit some
@@ -266,61 +303,70 @@ ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)
bool
ThreadPlanStepOut::ShouldStop (Event *event_ptr)
{
- if (IsPlanComplete())
- return true;
-
- bool done;
-
+ if (IsPlanComplete())
+ return true;
+
+ bool done = false;
+ if (m_step_out_to_inline_plan_sp)
+ {
+ if (m_step_out_to_inline_plan_sp->MischiefManaged())
+ {
+ // Now step through the inlined stack we are in:
+ if (QueueInlinedStepPlan(true))
+ {
+ // If we can't queue a plan to do this, then just call ourselves done.
+ m_step_out_to_inline_plan_sp.reset();
+ SetPlanComplete (false);
+ return true;
+ }
+ else
+ done = true;
+ }
+ else
+ return m_step_out_to_inline_plan_sp->ShouldStop(event_ptr);
+ }
+ else if (m_step_through_inline_plan_sp)
+ {
+ if (m_step_through_inline_plan_sp->MischiefManaged())
+ done = true;
+ else
+ return m_step_through_inline_plan_sp->ShouldStop(event_ptr);
+ }
+ else if (m_step_out_further_plan_sp)
+ {
+ if (m_step_out_further_plan_sp->MischiefManaged())
+ m_step_out_further_plan_sp.reset();
+ else
+ return m_step_out_further_plan_sp->ShouldStop(event_ptr);
+ }
+
+ if (!done)
+ {
StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
if (frame_zero_id < m_step_out_to_id)
done = false;
else
done = true;
-
- if (done)
+ }
+
+ // The normal step out computations think we are done, so all we need to do is consult the ShouldStopHere,
+ // and we are done.
+
+ if (done)
+ {
+ if (InvokeShouldStopHereCallback(eFrameCompareOlder))
{
CalculateReturnValue();
SetPlanComplete();
- return true;
}
else
{
- if (m_step_out_plan_sp)
- {
- if (m_step_out_plan_sp->MischiefManaged())
- {
- // Now step through the inlined stack we are in:
- if (QueueInlinedStepPlan(true))
- {
- return false;
- }
- else
- {
- CalculateReturnValue();
- SetPlanComplete ();
- return true;
- }
- }
- else
- return m_step_out_plan_sp->ShouldStop(event_ptr);
- }
- else if (m_step_through_inline_plan_sp)
- {
- if (m_step_through_inline_plan_sp->MischiefManaged())
- {
- // We don't calculate the return value here because we don't know how to.
- // But in case we had a return value sitting around from our process in
- // getting here, let's clear it out.
- m_return_valobj_sp.reset();
- SetPlanComplete();
- return true;
- }
- else
- return m_step_through_inline_plan_sp->ShouldStop(event_ptr);
- }
- else
- return false;
+ m_step_out_further_plan_sp = QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder);
+ done = false;
}
+ }
+
+ return done;
}
bool
@@ -338,7 +384,7 @@ ThreadPlanStepOut::GetPlanRunState ()
bool
ThreadPlanStepOut::DoWillResume (StateType resume_state, bool current_plan)
{
- if (m_step_out_plan_sp || m_step_through_inline_plan_sp)
+ if (m_step_out_to_inline_plan_sp || m_step_through_inline_plan_sp)
return true;
if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
@@ -427,10 +473,12 @@ ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now)
inlined_block->CalculateSymbolContext(&inlined_sc);
inlined_sc.target_sp = GetTarget().shared_from_this();
RunMode run_mode = m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads;
+ const LazyBool avoid_no_debug = eLazyBoolNo;
ThreadPlanStepOverRange *step_through_inline_plan_ptr = new ThreadPlanStepOverRange(m_thread,
inline_range,
inlined_sc,
- run_mode);
+ run_mode,
+ avoid_no_debug);
step_through_inline_plan_ptr->SetOkayToDiscard(true);
StreamString errors;
if (!step_through_inline_plan_ptr->ValidatePlan(&errors))
@@ -486,4 +534,3 @@ ThreadPlanStepOut::IsPlanStale()
else
return true;
}
-
diff --git a/source/Target/ThreadPlanStepOverRange.cpp b/source/Target/ThreadPlanStepOverRange.cpp
index 2d8108bf9b77..a4f3743346e2 100644
--- a/source/Target/ThreadPlanStepOverRange.cpp
+++ b/source/Target/ThreadPlanStepOverRange.cpp
@@ -31,6 +31,7 @@
using namespace lldb_private;
using namespace lldb;
+uint32_t ThreadPlanStepOverRange::s_default_flag_values = 0;
//----------------------------------------------------------------------
// ThreadPlanStepOverRange: Step through a stack range, either stepping over or into
@@ -42,11 +43,15 @@ ThreadPlanStepOverRange::ThreadPlanStepOverRange
Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others
+ lldb::RunMode stop_others,
+ LazyBool step_out_avoids_code_without_debug_info
) :
ThreadPlanStepRange (ThreadPlan::eKindStepOverRange, "Step range stepping over", thread, range, addr_context, stop_others),
+ ThreadPlanShouldStopHere (this),
m_first_resume(true)
{
+ SetFlagsToDefault();
+ SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
}
ThreadPlanStepOverRange::~ThreadPlanStepOverRange ()
@@ -65,6 +70,32 @@ ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level
}
}
+void
+ThreadPlanStepOverRange::SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info)
+{
+ bool avoid_nodebug = true;
+ switch (step_out_avoids_code_without_debug_info)
+ {
+ case eLazyBoolYes:
+ avoid_nodebug = true;
+ break;
+ case eLazyBoolNo:
+ avoid_nodebug = false;
+ break;
+ case eLazyBoolCalculate:
+ avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug();
+ break;
+ }
+ if (avoid_nodebug)
+ GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
+ else
+ GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug);
+ // Step Over plans should always avoid no-debug on step in. Seems like you shouldn't
+ // have to say this, but a tail call looks more like a step in that a step out, so
+ // we want to catch this case.
+ GetFlags().Set (ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
+}
+
bool
ThreadPlanStepOverRange::IsEquivalentContext(const SymbolContext &context)
{
@@ -146,18 +177,21 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
const SymbolContext &older_context = older_frame_sp->GetSymbolContext(eSymbolContextEverything);
if (IsEquivalentContext(older_context))
{
- new_plan_sp = m_thread.QueueThreadPlanForStepOut (false,
- NULL,
- true,
- stop_others,
- eVoteNo,
- eVoteNoOpinion,
- 0);
+ new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop (false,
+ NULL,
+ true,
+ stop_others,
+ eVoteNo,
+ eVoteNoOpinion,
+ 0);
break;
}
else
{
new_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
+ // If we found a way through, then we should stop recursing.
+ if (new_plan_sp)
+ break;
}
}
}
@@ -277,6 +311,13 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
// If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:
ClearNextBranchBreakpoint();
+
+ // If we haven't figured out something to do yet, then ask the ShouldStopHere callback:
+ if (!new_plan_sp)
+ {
+ new_plan_sp = CheckShouldStopHereAndQueueStepOut (frame_order);
+ }
+
if (!new_plan_sp)
m_no_more_plans = true;
else
@@ -390,3 +431,4 @@ ThreadPlanStepOverRange::DoWillResume (lldb::StateType resume_state, bool curren
return true;
}
+
diff --git a/source/Target/ThreadPlanStepRange.cpp b/source/Target/ThreadPlanStepRange.cpp
index 309f773c505b..82ca59fbca39 100644
--- a/source/Target/ThreadPlanStepRange.cpp
+++ b/source/Target/ThreadPlanStepRange.cpp
@@ -50,6 +50,7 @@ ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,
m_address_ranges (),
m_stop_others (stop_others),
m_stack_id (),
+ m_parent_stack_id(),
m_no_more_plans (false),
m_first_run_event (true),
m_use_fast_step(false)
@@ -57,6 +58,9 @@ ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,
m_use_fast_step = GetTarget().GetUseFastStepping();
AddRange(range);
m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+ StackFrameSP parent_stack = m_thread.GetStackFrameAtIndex(1);
+ if (parent_stack)
+ m_parent_stack_id = parent_stack->GetStackID();
}
ThreadPlanStepRange::~ThreadPlanStepRange ()
@@ -270,7 +274,16 @@ ThreadPlanStepRange::CompareCurrentFrameToStartFrame()
}
else
{
- frame_order = eFrameCompareOlder;
+ StackFrameSP cur_parent_frame = m_thread.GetStackFrameAtIndex(1);
+ StackID cur_parent_id;
+ if (cur_parent_frame)
+ cur_parent_id = cur_parent_frame->GetStackID();
+ if (m_parent_stack_id.IsValid()
+ && cur_parent_id.IsValid()
+ && m_parent_stack_id == cur_parent_id)
+ frame_order = eFrameCompareSameParent;
+ else
+ frame_order = eFrameCompareOlder;
}
return frame_order;
}
@@ -443,8 +456,8 @@ ThreadPlanStepRange::NextRangeBreakpointExplainsStop (lldb::StopInfoSP stop_info
}
}
if (log)
- log->Printf ("ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit next range breakpoint which has %zu owners - explains stop: %u.",
- num_owners,
+ log->Printf ("ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit next range breakpoint which has %" PRIu64 " owners - explains stop: %u.",
+ (uint64_t)num_owners,
explains_stop);
ClearNextBranchBreakpoint();
return explains_stop;
diff --git a/source/Target/ThreadPlanStepUntil.cpp b/source/Target/ThreadPlanStepUntil.cpp
index 62e05c7fe342..fa5ab8c5d491 100644
--- a/source/Target/ThreadPlanStepUntil.cpp
+++ b/source/Target/ThreadPlanStepUntil.cpp
@@ -77,7 +77,7 @@ ThreadPlanStepUntil::ThreadPlanStepUntil
}
}
- m_stack_id = m_thread.GetStackFrameAtIndex(frame_idx)->GetStackID();
+ m_stack_id = frame_sp->GetStackID();
// Now set breakpoints on all our return addresses:
for (size_t i = 0; i < num_addresses; i++)
diff --git a/source/Target/ThreadPlanTracer.cpp b/source/Target/ThreadPlanTracer.cpp
index d191170fcc08..5188df6d9193 100644
--- a/source/Target/ThreadPlanTracer.cpp
+++ b/source/Target/ThreadPlanTracer.cpp
@@ -166,17 +166,6 @@ ThreadPlanAssemblyTracer::TracingEnded ()
m_register_values.clear();
}
-static void
-PadOutTo (StreamString &stream, int target)
-{
- stream.Flush();
-
- int length = stream.GetString().length();
-
- if (length + 1 < target)
- stream.Printf("%*s", target - (length + 1) + 1, "");
-}
-
void
ThreadPlanAssemblyTracer::Log ()
{
diff --git a/source/Utility/ARM64_DWARF_Registers.cpp b/source/Utility/ARM64_DWARF_Registers.cpp
new file mode 100644
index 000000000000..d9b386319434
--- /dev/null
+++ b/source/Utility/ARM64_DWARF_Registers.cpp
@@ -0,0 +1,148 @@
+//===-- ARM64_DWARF_Registers.c ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <string.h>
+
+#include "ARM64_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace arm64_dwarf;
+
+const char *
+arm64_dwarf::GetRegisterName (unsigned reg_num, bool altnernate_name)
+{
+ if (altnernate_name)
+ {
+ switch (reg_num)
+ {
+ case fp: return "x29";
+ case lr: return "x30";
+ case sp: return "x31";
+ default:
+ break;
+ }
+ return nullptr;
+ }
+
+ switch (reg_num)
+ {
+ case x0: return "x0";
+ case x1: return "x1";
+ case x2: return "x2";
+ case x3: return "x3";
+ case x4: return "x4";
+ case x5: return "x5";
+ case x6: return "x6";
+ case x7: return "x7";
+ case x8: return "x8";
+ case x9: return "x9";
+ case x10: return "x10";
+ case x11: return "x11";
+ case x12: return "x12";
+ case x13: return "x13";
+ case x14: return "x14";
+ case x15: return "x15";
+ case x16: return "x16";
+ case x17: return "x17";
+ case x18: return "x18";
+ case x19: return "x19";
+ case x20: return "x20";
+ case x21: return "x21";
+ case x22: return "x22";
+ case x23: return "x23";
+ case x24: return "x24";
+ case x25: return "x25";
+ case x26: return "x26";
+ case x27: return "x27";
+ case x28: return "x28";
+ case fp: return "fp";
+ case lr: return "lr";
+ case sp: return "sp";
+ case pc: return "pc";
+ case cpsr: return "cpsr";
+ case v0: return "v0";
+ case v1: return "v1";
+ case v2: return "v2";
+ case v3: return "v3";
+ case v4: return "v4";
+ case v5: return "v5";
+ case v6: return "v6";
+ case v7: return "v7";
+ case v8: return "v8";
+ case v9: return "v9";
+ case v10: return "v10";
+ case v11: return "v11";
+ case v12: return "v12";
+ case v13: return "v13";
+ case v14: return "v14";
+ case v15: return "v15";
+ case v16: return "v16";
+ case v17: return "v17";
+ case v18: return "v18";
+ case v19: return "v19";
+ case v20: return "v20";
+ case v21: return "v21";
+ case v22: return "v22";
+ case v23: return "v23";
+ case v24: return "v24";
+ case v25: return "v25";
+ case v26: return "v26";
+ case v27: return "v27";
+ case v28: return "v28";
+ case v29: return "v29";
+ case v30: return "v30";
+ case v31: return "v31";
+ }
+ return nullptr;
+}
+
+bool
+arm64_dwarf::GetRegisterInfo (unsigned reg_num, RegisterInfo &reg_info)
+{
+ ::memset (&reg_info, 0, sizeof(RegisterInfo));
+ ::memset (reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
+
+ if (reg_num >= x0 && reg_num <= pc)
+ {
+ reg_info.byte_size = 8;
+ reg_info.format = eFormatHex;
+ reg_info.encoding = eEncodingUint;
+ }
+ else if (reg_num >= v0 && reg_num <= v31)
+ {
+ reg_info.byte_size = 16;
+ reg_info.format = eFormatVectorOfFloat32;
+ reg_info.encoding = eEncodingVector;
+ }
+ else if (reg_num == cpsr)
+ {
+ reg_info.byte_size = 4;
+ reg_info.format = eFormatHex;
+ reg_info.encoding = eEncodingUint;
+ }
+ else
+ {
+ return false;
+ }
+
+ reg_info.name = arm64_dwarf::GetRegisterName (reg_num, false);
+ reg_info.alt_name = arm64_dwarf::GetRegisterName (reg_num, true);
+ reg_info.kinds[eRegisterKindDWARF] = reg_num;
+
+ switch (reg_num)
+ {
+ case fp: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; break;
+ case lr: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; break;
+ case sp: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; break;
+ case pc: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; break;
+ default: break;
+ }
+ return true;
+}
diff --git a/source/Utility/ARM64_DWARF_Registers.h b/source/Utility/ARM64_DWARF_Registers.h
new file mode 100644
index 000000000000..832f25d45b5d
--- /dev/null
+++ b/source/Utility/ARM64_DWARF_Registers.h
@@ -0,0 +1,102 @@
+//===-- ARM64_DWARF_Registers.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef utility_ARM64_DWARF_Registers_h_
+#define utility_ARM64_DWARF_Registers_h_
+
+#include "lldb/lldb-private.h"
+
+namespace arm64_dwarf {
+
+enum
+{
+ x0 = 0,
+ x1,
+ x2,
+ x3,
+ x4,
+ x5,
+ x6,
+ x7,
+ x8,
+ x9,
+ x10,
+ x11,
+ x12,
+ x13,
+ x14,
+ x15,
+ x16,
+ x17,
+ x18,
+ x19,
+ x20,
+ x21,
+ x22,
+ x23,
+ x24,
+ x25,
+ x26,
+ x27,
+ x28,
+ x29 = 29, fp = x29,
+ x30 = 30, lr = x30,
+ x31 = 31, sp = x31,
+ pc = 32,
+ cpsr = 33,
+ // 34-63 reserved
+
+ // V0-V31 (128 bit vector registers)
+ v0 = 64,
+ v1,
+ v2,
+ v3,
+ v4,
+ v5,
+ v6,
+ v7,
+ v8,
+ v9,
+ v10,
+ v11,
+ v12,
+ v13,
+ v14,
+ v15,
+ v16,
+ v17,
+ v18,
+ v19,
+ v20,
+ v21,
+ v22,
+ v23,
+ v24,
+ v25,
+ v26,
+ v27,
+ v28,
+ v29,
+ v30,
+ v31
+
+ // 96-127 reserved
+};
+
+const char *
+GetRegisterName (unsigned reg_num, bool altnernate_name);
+
+bool
+GetRegisterInfo (unsigned reg_num,
+ lldb_private::RegisterInfo &reg_info);
+
+} // namespace arm64_dwarf
+
+#endif // utility_ARM64_DWARF_Registers_h_
+
diff --git a/source/Utility/ARM64_GCC_Registers.h b/source/Utility/ARM64_GCC_Registers.h
new file mode 100644
index 000000000000..2166b3bf591a
--- /dev/null
+++ b/source/Utility/ARM64_GCC_Registers.h
@@ -0,0 +1,92 @@
+//===-- ARM64_gdb_Registers.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef utility_ARM64_gdb_Registers_h_
+#define utility_ARM64_gdb_Registers_h_
+
+namespace arm64_gcc {
+
+enum
+{
+ x0 = 0,
+ x1,
+ x2,
+ x3,
+ x4,
+ x5,
+ x6,
+ x7,
+ x8,
+ x9,
+ x10,
+ x11,
+ x12,
+ x13,
+ x14,
+ x15,
+ x16,
+ x17,
+ x18,
+ x19,
+ x20,
+ x21,
+ x22,
+ x23,
+ x24,
+ x25,
+ x26,
+ x27,
+ x28,
+ fp, // aka x29
+ lr, // aka x30
+ sp, // aka x31 aka wzr
+ pc, // value is 32
+ cpsr
+};
+
+enum
+{
+ v0 = 64,
+ v1,
+ v2,
+ v3,
+ v4,
+ v5,
+ v6,
+ v7,
+ v8,
+ v9,
+ v10,
+ v11,
+ v12,
+ v13,
+ v14,
+ v15,
+ v16,
+ v17,
+ v18,
+ v19,
+ v20,
+ v21,
+ v22,
+ v23,
+ v24,
+ v25,
+ v26,
+ v27,
+ v28,
+ v29,
+ v30,
+ v31 // 95
+};
+
+}
+
+#endif // utility_ARM64_gdb_Registers_h_
+
diff --git a/source/Utility/ARM_DWARF_Registers.cpp b/source/Utility/ARM_DWARF_Registers.cpp
index 491ba040863e..64472ba1a79e 100644
--- a/source/Utility/ARM_DWARF_Registers.cpp
+++ b/source/Utility/ARM_DWARF_Registers.cpp
@@ -202,7 +202,7 @@ GetARMDWARFRegisterName (unsigned reg_num)
case dwarf_q14: return "q14";
case dwarf_q15: return "q15";
}
- return 0;
+ return nullptr;
}
bool
diff --git a/source/Utility/PseudoTerminal.cpp b/source/Utility/PseudoTerminal.cpp
index 98d581def4c3..c906ea273005 100644
--- a/source/Utility/PseudoTerminal.cpp
+++ b/source/Utility/PseudoTerminal.cpp
@@ -19,6 +19,7 @@
#ifdef _WIN32
#include "lldb/Host/windows/win32.h"
+typedef uint32_t pid_t;
// empty functions
int posix_openpt(int flag) { return 0; }
@@ -47,7 +48,7 @@ PseudoTerminal::PseudoTerminal () :
// Destructor
//
// The destructor will close the master and slave file descriptors
-// if they are valid and ownwership has not been released using the
+// if they are valid and ownership has not been released using the
// ReleaseMasterFileDescriptor() or the ReleaseSaveFileDescriptor()
// member functions.
//----------------------------------------------------------------------
@@ -155,7 +156,7 @@ PseudoTerminal::OpenSlave (int oflag, char *error_str, size_t error_len)
// Open the master side of a pseudo terminal
const char *slave_name = GetSlaveName (error_str, error_len);
- if (slave_name == NULL)
+ if (slave_name == nullptr)
return false;
m_slave_fd = ::open (slave_name, oflag);
@@ -193,11 +194,11 @@ PseudoTerminal::GetSlaveName (char *error_str, size_t error_len) const
{
if (error_str)
::snprintf (error_str, error_len, "%s", "master file descriptor is invalid");
- return NULL;
+ return nullptr;
}
const char *slave_name = ::ptsname (m_master_fd);
- if (error_str && slave_name == NULL)
+ if (error_str && slave_name == nullptr)
::strerror_r (errno, error_str, error_len);
return slave_name;
diff --git a/source/Utility/SharingPtr.cpp b/source/Utility/SharingPtr.cpp
index be237cec61c4..4083975bba7c 100644
--- a/source/Utility/SharingPtr.cpp
+++ b/source/Utility/SharingPtr.cpp
@@ -18,6 +18,8 @@
#include <assert.h>
#include "lldb/Host/Mutex.h"
+#include "llvm/ADT/STLExtras.h"
+
#include <vector>
class Backtrace
@@ -51,7 +53,7 @@ void
Backtrace::GetFrames ()
{
void *frames[1024];
- const int count = ::backtrace (frames, sizeof(frames)/sizeof(void*));
+ const int count = ::backtrace (frames, llvm::array_lengthof(frames));
if (count > 2)
m_frames.assign (frames + 2, frames + (count - 2));
}
diff --git a/source/Utility/StringExtractor.cpp b/source/Utility/StringExtractor.cpp
index 9d2315708821..8747853213cb 100644
--- a/source/Utility/StringExtractor.cpp
+++ b/source/Utility/StringExtractor.cpp
@@ -63,16 +63,6 @@ xdigit_to_sint (char ch)
return ch - '0';
}
-static inline unsigned int
-xdigit_to_uint (uint8_t ch)
-{
- if (ch >= 'a' && ch <= 'f')
- return 10u + ch - 'a';
- if (ch >= 'A' && ch <= 'F')
- return 10u + ch - 'A';
- return ch - '0';
-}
-
//----------------------------------------------------------------------
// StringExtractor constructor
//----------------------------------------------------------------------
@@ -165,7 +155,7 @@ StringExtractor::GetU32 (uint32_t fail_value, int base)
{
if (m_index < m_packet.size())
{
- char *end = NULL;
+ char *end = nullptr;
const char *start = m_packet.c_str();
const char *cstr = start + m_index;
uint32_t result = ::strtoul (cstr, &end, base);
@@ -184,7 +174,7 @@ StringExtractor::GetS32 (int32_t fail_value, int base)
{
if (m_index < m_packet.size())
{
- char *end = NULL;
+ char *end = nullptr;
const char *start = m_packet.c_str();
const char *cstr = start + m_index;
int32_t result = ::strtol (cstr, &end, base);
@@ -204,7 +194,7 @@ StringExtractor::GetU64 (uint64_t fail_value, int base)
{
if (m_index < m_packet.size())
{
- char *end = NULL;
+ char *end = nullptr;
const char *start = m_packet.c_str();
const char *cstr = start + m_index;
uint64_t result = ::strtoull (cstr, &end, base);
@@ -223,7 +213,7 @@ StringExtractor::GetS64 (int64_t fail_value, int base)
{
if (m_index < m_packet.size())
{
- char *end = NULL;
+ char *end = nullptr;
const char *start = m_packet.c_str();
const char *cstr = start + m_index;
int64_t result = ::strtoll (cstr, &end, base);
@@ -429,6 +419,18 @@ StringExtractor::GetHexByteString (std::string &str)
}
size_t
+StringExtractor::GetHexByteStringFixedLength (std::string &str, uint32_t nibble_length)
+{
+ str.clear();
+
+ uint32_t nibble_count = 0;
+ for (const char *pch = Peek(); (nibble_count < nibble_length) && (pch != nullptr); str.append(1, GetHexU8(0, false)), pch = Peek (), nibble_count += 2)
+ {}
+
+ return str.size();
+}
+
+size_t
StringExtractor::GetHexByteStringTerminatedBy (std::string &str,
char terminator)
{
@@ -438,6 +440,7 @@ StringExtractor::GetHexByteStringTerminatedBy (std::string &str,
str.append(1, ch);
if (Peek() && *Peek() == terminator)
return str.size();
+
str.clear();
return str.size();
}
diff --git a/source/Utility/StringExtractor.h b/source/Utility/StringExtractor.h
index 2aab3b09f47e..697499309ced 100644
--- a/source/Utility/StringExtractor.h
+++ b/source/Utility/StringExtractor.h
@@ -129,6 +129,9 @@ public:
GetHexByteString (std::string &str);
size_t
+ GetHexByteStringFixedLength (std::string &str, uint32_t nibble_length);
+
+ size_t
GetHexByteStringTerminatedBy (std::string &str,
char terminator);
@@ -137,7 +140,7 @@ public:
{
if (m_index < m_packet.size())
return m_packet.c_str() + m_index;
- return NULL;
+ return nullptr;
}
protected:
diff --git a/source/Utility/StringExtractorGDBRemote.cpp b/source/Utility/StringExtractorGDBRemote.cpp
index eccb81318131..17717dbe6e20 100644
--- a/source/Utility/StringExtractorGDBRemote.cpp
+++ b/source/Utility/StringExtractorGDBRemote.cpp
@@ -92,6 +92,7 @@ StringExtractorGDBRemote::GetServerPacketType () const
if (PACKET_MATCHES ("QStartNoAckMode")) return eServerPacketType_QStartNoAckMode;
if (PACKET_STARTS_WITH ("QSaveRegisterState")) return eServerPacketType_QSaveRegisterState;
if (PACKET_STARTS_WITH ("QSetDisableASLR:")) return eServerPacketType_QSetDisableASLR;
+ if (PACKET_STARTS_WITH ("QSetDetachOnError:")) return eServerPacketType_QSetDetachOnError;
if (PACKET_STARTS_WITH ("QSetSTDIN:")) return eServerPacketType_QSetSTDIN;
if (PACKET_STARTS_WITH ("QSetSTDOUT:")) return eServerPacketType_QSetSTDOUT;
if (PACKET_STARTS_WITH ("QSetSTDERR:")) return eServerPacketType_QSetSTDERR;
@@ -178,6 +179,7 @@ StringExtractorGDBRemote::GetServerPacketType () const
if (PACKET_STARTS_WITH ("qSpeedTest:")) return eServerPacketType_qSpeedTest;
if (PACKET_MATCHES ("qShlibInfoAddr")) return eServerPacketType_qShlibInfoAddr;
if (PACKET_MATCHES ("qStepPacketSupported")) return eServerPacketType_qStepPacketSupported;
+ if (PACKET_STARTS_WITH ("qSupported")) return eServerPacketType_qSupported;
if (PACKET_MATCHES ("qSyncThreadStateSupported")) return eServerPacketType_qSyncThreadStateSupported;
break;
@@ -198,6 +200,10 @@ StringExtractorGDBRemote::GetServerPacketType () const
if (PACKET_STARTS_WITH ("qWatchpointSupportInfo:")) return eServerPacketType_qWatchpointSupportInfo;
if (PACKET_MATCHES ("qWatchpointSupportInfo")) return eServerPacketType_qWatchpointSupportInfoSupported;
break;
+
+ case 'X':
+ if (PACKET_STARTS_WITH ("qXfer:auxv:read::")) return eServerPacketType_qXfer_auxv_read;
+ break;
}
break;
case 'v':
diff --git a/source/Utility/StringExtractorGDBRemote.h b/source/Utility/StringExtractorGDBRemote.h
index f8af3ca41a79..e16403c2d154 100644
--- a/source/Utility/StringExtractorGDBRemote.h
+++ b/source/Utility/StringExtractorGDBRemote.h
@@ -62,6 +62,7 @@ public:
eServerPacketType_QEnvironment,
eServerPacketType_QLaunchArch,
eServerPacketType_QSetDisableASLR,
+ eServerPacketType_QSetDetachOnError,
eServerPacketType_QSetSTDIN,
eServerPacketType_QSetSTDOUT,
eServerPacketType_QSetSTDERR,
@@ -105,12 +106,14 @@ public:
eServerPacketType_qRegisterInfo,
eServerPacketType_qShlibInfoAddr,
eServerPacketType_qStepPacketSupported,
+ eServerPacketType_qSupported,
eServerPacketType_qSyncThreadStateSupported,
eServerPacketType_qThreadExtraInfo,
eServerPacketType_qThreadStopInfo,
eServerPacketType_qVAttachOrWaitSupported,
eServerPacketType_qWatchpointSupportInfo,
eServerPacketType_qWatchpointSupportInfoSupported,
+ eServerPacketType_qXfer_auxv_read,
eServerPacketType_vAttach,
eServerPacketType_vAttachWait,
diff --git a/source/Utility/StringLexer.cpp b/source/Utility/StringLexer.cpp
new file mode 100644
index 000000000000..bde2fc6a4202
--- /dev/null
+++ b/source/Utility/StringLexer.cpp
@@ -0,0 +1,101 @@
+//===--------------------- StringLexer.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/Utility/StringLexer.h"
+
+#include <algorithm>
+
+using namespace lldb_utility;
+
+StringLexer::StringLexer (std::string s) :
+m_data(s),
+m_position(0),
+m_putback_data()
+{ }
+
+StringLexer::StringLexer (const StringLexer& rhs) :
+m_data(rhs.m_data),
+m_position(rhs.m_position),
+m_putback_data(rhs.m_putback_data)
+{ }
+
+StringLexer::Character
+StringLexer::Peek ()
+{
+ if (m_putback_data.empty())
+ return m_data[m_position];
+ else
+ return m_putback_data.front();
+}
+
+bool
+StringLexer::NextIf (Character c)
+{
+ auto val = Peek();
+ if (val == c)
+ {
+ Next();
+ return true;
+ }
+ return false;
+}
+
+StringLexer::Character
+StringLexer::Next ()
+{
+ auto val = Peek();
+ Consume();
+ return val;
+}
+
+bool
+StringLexer::HasAtLeast (Size s)
+{
+ auto in_m_data = m_data.size()-m_position;
+ auto in_putback = m_putback_data.size();
+ return (in_m_data + in_putback >= s);
+}
+
+
+void
+StringLexer::PutBack (Character c)
+{
+ m_putback_data.push_back(c);
+}
+
+bool
+StringLexer::HasAny (Character c)
+{
+ const auto begin(m_putback_data.begin());
+ const auto end(m_putback_data.end());
+ if (std::find(begin, end, c) != end)
+ return true;
+ return m_data.find(c, m_position) != std::string::npos;
+}
+
+void
+StringLexer::Consume()
+{
+ if (m_putback_data.empty())
+ m_position++;
+ else
+ m_putback_data.pop_front();
+}
+
+StringLexer&
+StringLexer::operator = (const StringLexer& rhs)
+{
+ if (this != &rhs)
+ {
+ m_data = rhs.m_data;
+ m_position = rhs.m_position;
+ m_putback_data = rhs.m_putback_data;
+ }
+ return *this;
+}
diff --git a/source/Utility/TimeSpecTimeout.h b/source/Utility/TimeSpecTimeout.h
index 32cdd067658c..388ccc179c17 100644
--- a/source/Utility/TimeSpecTimeout.h
+++ b/source/Utility/TimeSpecTimeout.h
@@ -76,7 +76,7 @@ public:
GetTimeSpecPtr () const
{
if (m_infinite)
- return NULL;
+ return nullptr;
return &m_timespec;
}
diff --git a/source/lldb-log.cpp b/source/lldb-log.cpp
index 12ec3a546e1b..4311c1ad084f 100644
--- a/source/lldb-log.cpp
+++ b/source/lldb-log.cpp
@@ -145,6 +145,7 @@ lldb_private::DisableLog (const char **categories, Stream *feedback_strm)
else if (0 == ::strncasecmp(arg, "module", 6)) flag_bits &= ~LIBLLDB_LOG_MODULES;
else if (0 == ::strncasecmp(arg, "mmap", 4)) flag_bits &= ~LIBLLDB_LOG_MMAP;
else if (0 == ::strcasecmp(arg, "os")) flag_bits &= ~LIBLLDB_LOG_OS;
+ else if (0 == ::strcasecmp(arg, "jit")) flag_bits &= ~LIBLLDB_LOG_JIT_LOADER;
else
{
feedback_strm->Printf ("error: unrecognized log category '%s'\n", arg);
@@ -220,6 +221,7 @@ lldb_private::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const ch
else if (0 == ::strncasecmp(arg, "unwind", 6)) flag_bits |= LIBLLDB_LOG_UNWIND;
else if (0 == ::strcasecmp(arg, "verbose")) flag_bits |= LIBLLDB_LOG_VERBOSE;
else if (0 == ::strncasecmp(arg, "watch", 5)) flag_bits |= LIBLLDB_LOG_WATCHPOINTS;
+ else if (0 == ::strcasecmp(arg, "jit")) flag_bits |= LIBLLDB_LOG_JIT_LOADER;
else
{
feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
@@ -251,8 +253,9 @@ lldb_private::ListLogCategories (Stream *strm)
" events - log broadcaster, listener and event queue activities\n"
" expr - log expressions\n"
" host - log host activities\n"
+ " jit - log JIT events in the target\n"
" mmap - log mmap related activities\n"
- " module - log module activities such as when modules are created, detroyed, replaced, and more\n"
+ " module - log module activities such as when modules are created, destroyed, replaced, and more\n"
" object - log object construction/destruction for important objects\n"
" os - log OperatingSystem plugin related activities\n"
" platform - log platform events and activities\n"
diff --git a/source/lldb.cpp b/source/lldb.cpp
index 4817e7f2b44c..cd620b7945b9 100644
--- a/source/lldb.cpp
+++ b/source/lldb.cpp
@@ -18,34 +18,43 @@
#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/Timer.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Interpreter/ScriptInterpreterPython.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/TargetSelect.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-x86_64/ABISysV_x86_64.h"
#include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h"
+#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
#include "Plugins/Instruction/ARM/EmulateInstructionARM.h"
+#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
#include "Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h"
-#include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h"
+#include "Plugins/JITLoader/GDB/JITLoaderGDB.h"
+#include "Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h"
#include "Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h"
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
-#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
-#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h"
-#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
-#include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h"
-#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
-#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
#include "Plugins/Platform/FreeBSD/PlatformFreeBSD.h"
#include "Plugins/Platform/Linux/PlatformLinux.h"
#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
#include "Plugins/Platform/Windows/PlatformWindows.h"
-#include "Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h"
+#include "Plugins/Platform/Kalimba/PlatformKalimba.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+#include "Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h"
+#include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h"
+#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
+#include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h"
+#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
+
#ifndef LLDB_DISABLE_PYTHON
#include "Plugins/OperatingSystem/Python/OperatingSystemPython.h"
#endif
@@ -66,14 +75,15 @@
#include "Plugins/Process/mach-core/ProcessMachCore.h"
-#if defined(__linux__) || defined(__FreeBSD__)
-#include "Plugins/Process/elf-core/ProcessElfCore.h"
-#endif
#if defined (__linux__)
#include "Plugins/Process/Linux/ProcessLinux.h"
#endif
+#if defined (_WIN32)
+#include "Plugins/Process/Windows/ProcessWindows.h"
+#endif
+
#if defined (__FreeBSD__)
#include "Plugins/Process/POSIX/ProcessPOSIX.h"
#include "Plugins/Process/FreeBSD/ProcessFreeBSD.h"
@@ -86,6 +96,12 @@
using namespace lldb;
using namespace lldb_private;
+static void fatal_error_handler(void *user_data, const std::string& reason,
+ bool gen_crash_diag) {
+ Host::SetCrashDescription(reason.c_str());
+ ::abort();
+}
+
void
lldb_private::Initialize ()
{
@@ -98,11 +114,21 @@ lldb_private::Initialize ()
{
g_inited = true;
Log::Initialize();
+ HostInfo::Initialize();
Timer::Initialize ();
Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
-
+
+ // Initialize LLVM and Clang
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllDisassemblers();
+ llvm::install_fatal_error_handler(fatal_error_handler, 0);
+
+ // Initialize plug-ins
ABIMacOSX_i386::Initialize();
ABIMacOSX_arm::Initialize();
+ ABIMacOSX_arm64::Initialize();
ABISysV_x86_64::Initialize();
DisassemblerLLVMC::Initialize();
ObjectContainerBSDArchive::Initialize();
@@ -113,18 +139,22 @@ lldb_private::Initialize ()
UnwindAssemblyInstEmulation::Initialize();
UnwindAssembly_x86::Initialize();
EmulateInstructionARM::Initialize ();
+ EmulateInstructionARM64::Initialize ();
ObjectFilePECOFF::Initialize ();
DynamicLoaderPOSIXDYLD::Initialize ();
PlatformFreeBSD::Initialize();
PlatformLinux::Initialize();
PlatformWindows::Initialize();
+ PlatformKalimba::Initialize();
SymbolFileDWARFDebugMap::Initialize();
ItaniumABILanguageRuntime::Initialize();
#ifndef LLDB_DISABLE_PYTHON
ScriptInterpreterPython::InitializePrivate();
OperatingSystemPython::Initialize();
#endif
-
+ JITLoaderGDB::Initialize();
+ ProcessElfCore::Initialize();
+
#if defined (__APPLE__)
//----------------------------------------------------------------------
// Apple/Darwin hosted plugins
@@ -150,13 +180,13 @@ lldb_private::Initialize ()
//----------------------------------------------------------------------
ProcessLinux::Initialize();
#endif
+#if defined(_WIN32)
+ ProcessWindows::Initialize();
+#endif
#if defined (__FreeBSD__)
ProcessFreeBSD::Initialize();
#endif
-#if defined(__linux__) || defined(__FreeBSD__)
- ProcessElfCore::Initialize();
-#endif
//----------------------------------------------------------------------
// Platform agnostic plugins
//----------------------------------------------------------------------
@@ -189,6 +219,7 @@ lldb_private::Terminate ()
PluginManager::Terminate();
ABIMacOSX_i386::Terminate();
ABIMacOSX_arm::Terminate();
+ ABIMacOSX_arm64::Terminate();
ABISysV_x86_64::Terminate();
DisassemblerLLVMC::Terminate();
ObjectContainerBSDArchive::Terminate();
@@ -199,17 +230,21 @@ lldb_private::Terminate ()
UnwindAssembly_x86::Terminate();
UnwindAssemblyInstEmulation::Terminate();
EmulateInstructionARM::Terminate ();
+ EmulateInstructionARM64::Terminate ();
ObjectFilePECOFF::Terminate ();
DynamicLoaderPOSIXDYLD::Terminate ();
PlatformFreeBSD::Terminate();
PlatformLinux::Terminate();
PlatformWindows::Terminate();
+ PlatformKalimba::Terminate();
SymbolFileDWARFDebugMap::Terminate();
ItaniumABILanguageRuntime::Terminate();
#ifndef LLDB_DISABLE_PYTHON
OperatingSystemPython::Terminate();
#endif
-
+ JITLoaderGDB::Terminate();
+ ProcessElfCore::Terminate();
+
#if defined (__APPLE__)
DynamicLoaderMacOSXDYLD::Terminate();
DynamicLoaderDarwinKernel::Terminate();
@@ -237,9 +272,6 @@ lldb_private::Terminate ()
ProcessFreeBSD::Terminate();
#endif
-#if defined(__linux__) || defined(__FreeBSD__)
- ProcessElfCore::Terminate();
-#endif
ProcessGDBRemote::Terminate();
DynamicLoaderStatic::Terminate();
@@ -292,7 +324,8 @@ lldb_private::GetVersion ()
size_t version_len = sizeof(g_version_string);
- if (newline_loc && (newline_loc - version_string < version_len))
+ if (newline_loc &&
+ (newline_loc - version_string < static_cast<ptrdiff_t>(version_len)))
version_len = newline_loc - version_string;
::strncpy(g_version_string, version_string, version_len);
diff --git a/tools/driver/Driver.cpp b/tools/driver/Driver.cpp
index 78d3a7e1c037..854310031c37 100644
--- a/tools/driver/Driver.cpp
+++ b/tools/driver/Driver.cpp
@@ -15,6 +15,14 @@
#include <limits.h>
#include <fcntl.h>
+// Includes for pipe()
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#else
+#include <unistd.h>
+#endif
+
#include <string>
#include <thread>
@@ -477,63 +485,19 @@ Driver::GetScriptLanguage() const
}
void
-Driver::ExecuteInitialCommands (bool before_file)
+Driver::WriteInitialCommands (bool before_file, SBStream &strm)
{
- size_t num_commands;
- std::vector<std::pair<bool, std::string> > *command_set;
- if (before_file)
- command_set = &(m_option_data.m_initial_commands);
- else
- command_set = &(m_option_data.m_after_file_commands);
+ std::vector<std::pair<bool, std::string> > &command_set = before_file ? m_option_data.m_initial_commands :
+ m_option_data.m_after_file_commands;
- num_commands = command_set->size();
- SBCommandReturnObject result;
- bool old_async = GetDebugger().GetAsync();
- GetDebugger().SetAsync(false);
- for (size_t idx = 0; idx < num_commands; idx++)
+ for (const auto &command_pair : command_set)
{
- bool is_file = (*command_set)[idx].first;
- const char *command = (*command_set)[idx].second.c_str();
- char command_string[PATH_MAX * 2];
- const bool dump_stream_only_if_no_immediate = true;
- const char *executed_command = command;
- if (is_file)
- {
- ::snprintf (command_string, sizeof(command_string), "command source -s %i '%s'", m_option_data.m_source_quietly, command);
- executed_command = command_string;
- }
-
- m_debugger.GetCommandInterpreter().HandleCommand (executed_command, result, false);
- if (!m_option_data.m_source_quietly || result.Succeeded() == false)
- {
- const size_t output_size = result.GetOutputSize();
- if (output_size > 0)
- {
- const char *cstr = result.GetOutput(dump_stream_only_if_no_immediate);
- if (cstr)
- printf ("%s", cstr);
- }
- const size_t error_size = result.GetErrorSize();
- if (error_size > 0)
- {
- const char *cstr = result.GetError(dump_stream_only_if_no_immediate);
- if (cstr)
- printf ("%s", cstr);
- }
- }
-
- if (result.Succeeded() == false)
- {
- const char *type = before_file ? "before file" : "after_file";
- if (is_file)
- ::fprintf(stderr, "Aborting %s command execution, command file: '%s' failed.\n", type, command);
- else
- ::fprintf(stderr, "Aborting %s command execution, command: '%s' failed.\n", type, command);
- break;
- }
- result.Clear();
+ const char *command = command_pair.second.c_str();
+ if (command_pair.first)
+ strm.Printf("command source -s %i '%s'\n", m_option_data.m_source_quietly, command);
+ else
+ strm.Printf("%s\n", command);
}
- GetDebugger().SetAsync(old_async);
}
bool
@@ -857,8 +821,8 @@ Driver::MainLoop ()
m_debugger.SetErrorFileHandle (stderr, false);
m_debugger.SetOutputFileHandle (stdout, false);
- m_debugger.SetInputFileHandle (stdin, true);
-
+ m_debugger.SetInputFileHandle (stdin, false); // Don't take ownership of STDIN yet...
+
m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
struct winsize window_size;
@@ -882,77 +846,61 @@ Driver::MainLoop ()
}
// Now we handle options we got from the command line
- // First source in the commands specified to be run before the file arguments are processed.
- ExecuteInitialCommands(true);
-
- // Was there a core file specified?
- std::string core_file_spec("");
- if (!m_option_data.m_core_file.empty())
- core_file_spec.append("--core ").append(m_option_data.m_core_file);
+ SBStream commands_stream;
- char command_string[PATH_MAX * 2];
+ // First source in the commands specified to be run before the file arguments are processed.
+ WriteInitialCommands(true, commands_stream);
+
const size_t num_args = m_option_data.m_args.size();
if (num_args > 0)
{
char arch_name[64];
if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name)))
- ::snprintf (command_string,
- sizeof (command_string),
- "target create --arch=%s %s \"%s\"",
- arch_name,
- core_file_spec.c_str(),
- m_option_data.m_args[0].c_str());
+ commands_stream.Printf("target create --arch=%s \"%s\"", arch_name, m_option_data.m_args[0].c_str());
else
- ::snprintf (command_string,
- sizeof(command_string),
- "target create %s \"%s\"",
- core_file_spec.c_str(),
- m_option_data.m_args[0].c_str());
-
- m_debugger.HandleCommand (command_string);
+ commands_stream.Printf("target create \"%s\"", m_option_data.m_args[0].c_str());
+
+ if (!m_option_data.m_core_file.empty())
+ {
+ commands_stream.Printf(" --core \"%s\"", m_option_data.m_core_file.c_str());
+ }
+ commands_stream.Printf("\n");
if (num_args > 1)
{
- m_debugger.HandleCommand ("settings clear target.run-args");
- char arg_cstr[1024];
+ commands_stream.Printf ("settings set -- target.run-args ");
for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
{
- ::snprintf (arg_cstr,
- sizeof(arg_cstr),
- "settings append target.run-args \"%s\"",
- m_option_data.m_args[arg_idx].c_str());
- m_debugger.HandleCommand (arg_cstr);
+ const char *arg_cstr = m_option_data.m_args[arg_idx].c_str();
+ if (strchr(arg_cstr, '"') == NULL)
+ commands_stream.Printf(" \"%s\"", arg_cstr);
+ else
+ commands_stream.Printf(" '%s'", arg_cstr);
}
+ commands_stream.Printf("\n");
}
}
- else if (!core_file_spec.empty())
+ else if (!m_option_data.m_core_file.empty())
{
- ::snprintf (command_string,
- sizeof(command_string),
- "target create %s",
- core_file_spec.c_str());
- m_debugger.HandleCommand (command_string);;
+ commands_stream.Printf("target create --core \"%s\"\n", m_option_data.m_core_file.c_str());
}
else if (!m_option_data.m_process_name.empty())
{
- ::snprintf (command_string,
- sizeof(command_string),
- "process attach --name '%s'%s",
- m_option_data.m_process_name.c_str(),
- m_option_data.m_wait_for ? " --waitfor" : "");
- m_debugger.HandleCommand (command_string);
+ commands_stream.Printf ("process attach --name \"%s\"", m_option_data.m_process_name.c_str());
+
+ if (m_option_data.m_wait_for)
+ commands_stream.Printf(" --waitfor");
+
+ commands_stream.Printf("\n");
+
}
else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid)
{
- ::snprintf (command_string,
- sizeof(command_string),
- "process attach --pid %" PRIu64,
- m_option_data.m_process_pid);
- m_debugger.HandleCommand (command_string);
+ commands_stream.Printf ("process attach --pid %" PRIu64 "\n", m_option_data.m_process_pid);
}
- ExecuteInitialCommands(false);
-
+ WriteInitialCommands(false, commands_stream);
+
// Now that all option parsing is done, we try and parse the .lldbinit
// file in the current working directory
sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result);
@@ -964,6 +912,90 @@ Driver::MainLoop ()
bool handle_events = true;
bool spawn_thread = false;
+
+ // Check if we have any data in the commands stream, and if so, save it to a temp file
+ // so we can then run the command interpreter using the file contents.
+ const char *commands_data = commands_stream.GetData();
+ const size_t commands_size = commands_stream.GetSize();
+ if (commands_data && commands_size)
+ {
+ enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
+
+ bool success = true;
+ int fds[2] = { -1, -1 };
+ int err = 0;
+#ifdef _WIN32
+ err = _pipe(fds, commands_size, O_BINARY);
+#else
+ err = pipe(fds);
+#endif
+ if (err == 0)
+ {
+ if (write (fds[WRITE], commands_data, commands_size) == commands_size)
+ {
+ // Close the write end of the pipe so when we give the read end to
+ // the debugger/command interpreter it will exit when it consumes all
+ // of the data
+#ifdef _WIN32
+ _close(fds[WRITE]); fds[WRITE] = -1;
+#else
+ close(fds[WRITE]); fds[WRITE] = -1;
+#endif
+ // Now open the read file descriptor in a FILE * that we can give to
+ // the debugger as an input handle
+ FILE *commands_file = fdopen(fds[READ], "r");
+ if (commands_file)
+ {
+ fds[READ] = -1; // The FILE * 'commands_file' now owns the read descriptor
+ // Hand ownership if the FILE * over to the debugger for "commands_file".
+ m_debugger.SetInputFileHandle (commands_file, true);
+ m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
+ }
+ else
+ {
+ fprintf(stderr, "error: fdopen(%i, \"r\") failed (errno = %i) when trying to open LLDB commands pipe\n", fds[READ], errno);
+ success = false;
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr, "error: can't create pipe file descriptors for LLDB commands\n");
+ success = false;
+ }
+
+ // Close any pipes that we still have ownership of
+ if ( fds[WRITE] != -1)
+ {
+#ifdef _WIN32
+ _close(fds[WRITE]); fds[WRITE] = -1;
+#else
+ close(fds[WRITE]); fds[WRITE] = -1;
+#endif
+
+ }
+
+ if ( fds[READ] != -1)
+ {
+#ifdef _WIN32
+ _close(fds[READ]); fds[READ] = -1;
+#else
+ close(fds[READ]); fds[READ] = -1;
+#endif
+ }
+
+ // Something went wrong with command pipe
+ if (!success)
+ {
+ exit(1);
+ }
+
+ }
+
+ // Now set the input file handle to STDIN and run the command
+ // interpreter again in interactive mode and let the debugger
+ // take ownership of stdin
+ m_debugger.SetInputFileHandle (stdin, true);
m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
reset_stdin_termios();
@@ -1032,6 +1064,12 @@ sigcont_handler (int signo)
int
main (int argc, char const *argv[], const char *envp[])
{
+#ifdef _MSC_VER
+ // disable buffering on windows
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stdin , NULL, _IONBF, 0);
+#endif
+
SBDebugger::Initialize();
SBHostOS::ThreadCreated ("<lldb.driver.main-thread>");
diff --git a/tools/driver/Driver.h b/tools/driver/Driver.h
index 699244685d06..8b6c6eebdd56 100644
--- a/tools/driver/Driver.h
+++ b/tools/driver/Driver.h
@@ -23,9 +23,6 @@
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBError.h"
-#define ASYNC true
-#define NO_ASYNC false
-
class IOChannel;
class Driver : public lldb::SBBroadcaster
@@ -55,7 +52,7 @@ public:
GetScriptLanguage() const;
void
- ExecuteInitialCommands (bool before_file);
+ WriteInitialCommands (bool before_file, lldb::SBStream &strm);
bool
GetDebugMode() const;
diff --git a/tools/driver/Platform.cpp b/tools/driver/Platform.cpp
index 5b5286e68114..a49161540872 100644
--- a/tools/driver/Platform.cpp
+++ b/tools/driver/Platform.cpp
@@ -8,17 +8,14 @@
//===----------------------------------------------------------------------===//
// this file is only relevant for Visual C++
-#if defined( _MSC_VER )
+#if defined( _WIN32 )
#include <process.h>
#include <assert.h>
+#include <stdlib.h>
#include "Platform.h"
-// index one of the variable arguments
-// presuming "(EditLine *el, ..." is first in the argument list
-#define GETARG( Y, X ) ( (void* ) *( ( (int**) &(Y) ) + (X) ) )
-
// the control handler or SIGINT handler
static sighandler_t _ctrlHandler = NULL;
@@ -42,14 +39,16 @@ ioctl (int d, int request, ...)
// request the console windows size
case ( TIOCGWINSZ ):
{
- // locate the window size structure on stack
- winsize *ws = (winsize*) GETARG( d, 2 );
+ va_list vl;
+ va_start(vl,request);
+ // locate the window size structure on stack
+ winsize *ws = va_arg(vl, winsize*);
// get screen buffer information
CONSOLE_SCREEN_BUFFER_INFO info;
- GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &info );
- // fill in the columns
- ws->ws_col = info.dwMaximumWindowSize.X;
- //
+ if ( GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &info ) == TRUE )
+ // fill in the columns
+ ws->ws_col = info.dwMaximumWindowSize.X;
+ va_end(vl);
return 0;
}
break;
@@ -85,6 +84,7 @@ tcgetattr (int fildes, struct termios *termios_p)
return -1;
}
+#ifdef _MSC_VER
sighandler_t
signal (int sig, sighandler_t sigFunc)
{
@@ -107,5 +107,6 @@ signal (int sig, sighandler_t sigFunc)
}
return 0;
}
+#endif
-#endif \ No newline at end of file
+#endif
diff --git a/tools/driver/Platform.h b/tools/driver/Platform.h
index faa2991bf6f3..e26610711aca 100644
--- a/tools/driver/Platform.h
+++ b/tools/driver/Platform.h
@@ -10,22 +10,18 @@
#ifndef lldb_Platform_h_
#define lldb_Platform_h_
-#if defined( _MSC_VER )
+#include "lldb/Host/HostGetOpt.h"
+
+#if defined( _WIN32 )
// this will stop signal.h being included
#define _INC_SIGNAL
-
#include <io.h>
+#if defined( _MSC_VER )
#include <eh.h>
+#endif
#include <inttypes.h>
- #include "lldb/Host/windows/Windows.h"
- #include "lldb/Host/HostGetOpt.h"
-
- struct timeval
- {
- long tv_sec;
- long tv_usec;
- };
+ #include "lldb/Host/windows/windows.h"
struct winsize
{
@@ -42,6 +38,17 @@
// ioctls.h
#define TIOCGWINSZ 0x5413
+
+ // signal handler function pointer type
+ typedef void(*sighandler_t)(int);
+
+ // signal.h
+ #define SIGINT 2
+ // default handler
+ #define SIG_DFL ( (sighandler_t) -1 )
+ // ignored
+ #define SIG_IGN ( (sighandler_t) -2 )
+
// signal.h
#define SIGPIPE 13
#define SIGCONT 18
@@ -64,34 +71,31 @@
speed_t c_ospeed; // output speed
};
- typedef long pid_t;
- #define STDIN_FILENO 0
- #define PATH_MAX MAX_PATH
+#ifdef _MSC_VER
+ struct timeval
+ {
+ long tv_sec;
+ long tv_usec;
+ };
+ typedef long pid_t;
#define snprintf _snprintf
+ extern sighandler_t signal( int sig, sighandler_t );
+ #define PATH_MAX MAX_PATH
+#endif
+
+ #define STDIN_FILENO 0
extern int ioctl( int d, int request, ... );
extern int kill ( pid_t pid, int sig );
extern int tcsetattr( int fd, int optional_actions, const struct termios *termios_p );
extern int tcgetattr( int fildes, struct termios *termios_p );
- // signal handler function pointer type
- typedef void (*sighandler_t)(int);
-
- // signal.h
- #define SIGINT 2
- // default handler
- #define SIG_DFL ( (sighandler_t) -1 )
- // ignored
- #define SIG_IGN ( (sighandler_t) -2 )
- extern sighandler_t signal( int sig, sighandler_t );
-
#else
#include <inttypes.h>
- #include <getopt.h>
#include <libgen.h>
#include <sys/ioctl.h>
#include <termios.h>
@@ -101,7 +105,7 @@
#include <pthread.h>
#include <sys/time.h>
- #if defined(__FreeBSD__)
+ #if defined(__FreeBSD__) || defined(__NetBSD__)
#include <readline/readline.h>
#else
#include <editline/readline.h>
diff --git a/tools/lldb-mi/Driver.cpp b/tools/lldb-mi/Driver.cpp
new file mode 100644
index 000000000000..a59b4b74eb0a
--- /dev/null
+++ b/tools/lldb-mi/Driver.cpp
@@ -0,0 +1,1299 @@
+//===-- Driver.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// In-house headers:
+#include "MICmnConfig.h"
+
+#if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
+
+#ifndef _MSC_VER
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <string>
+#endif // _MSC_VER
+
+#include "Platform.h" // CODETAG_IOR_SIGNALS
+#include "Driver.h"
+
+#ifdef _MSC_VER
+#include <lldb\Host\windows\getopt\GetOptInc.h>
+#endif // _MSC_VER
+#include <lldb/API/SBBreakpoint.h>
+#include <lldb/API/SBCommandInterpreter.h>
+#include <lldb/API/SBCommandReturnObject.h>
+#include <lldb/API/SBCommunication.h>
+#include <lldb/API/SBEvent.h>
+#include <lldb/API/SBHostOS.h>
+#include <lldb/API/SBListener.h>
+#include <lldb/API/SBStream.h>
+#include <lldb/API/SBTarget.h>
+#include <lldb/API/SBThread.h>
+#include <lldb/API/SBProcess.h>
+
+using namespace lldb;
+
+static void reset_stdin_termios ();
+static bool g_old_stdin_termios_is_valid = false;
+static struct termios g_old_stdin_termios;
+
+static char *g_debugger_name = (char *) "";
+Driver *g_driver = NULL;
+
+// In the Driver::MainLoop, we change the terminal settings. This function is
+// added as an atexit handler to make sure we clean them up.
+static void
+reset_stdin_termios ()
+{
+ if (g_old_stdin_termios_is_valid)
+ {
+ g_old_stdin_termios_is_valid = false;
+ ::tcsetattr (STDIN_FILENO, TCSANOW, &g_old_stdin_termios);
+ }
+}
+
+typedef struct
+{
+ uint32_t usage_mask; // Used to mark options that can be used together. If (1 << n & usage_mask) != 0
+ // then this option belongs to option set n.
+ bool required; // This option is required (in the current usage level)
+ const char * long_option; // Full name for this option.
+ int short_option; // Single character for this option.
+ int option_has_arg; // no_argument, required_argument or optional_argument
+ uint32_t completion_type; // Cookie the option class can use to do define the argument completion.
+ lldb::CommandArgumentType argument_type; // Type of argument this option takes
+ const char * usage_text; // Full text explaining what this options does and what (if any) argument to
+ // pass it.
+} OptionDefinition;
+
+#define LLDB_3_TO_5 LLDB_OPT_SET_3|LLDB_OPT_SET_4|LLDB_OPT_SET_5
+#define LLDB_4_TO_5 LLDB_OPT_SET_4|LLDB_OPT_SET_5
+
+static OptionDefinition g_options[] =
+{
+ { LLDB_OPT_SET_1, true , "help" , 'h', no_argument , 0, eArgTypeNone,
+ "Prints out the usage information for the LLDB debugger." },
+ { LLDB_OPT_SET_2, true , "version" , 'v', no_argument , 0, eArgTypeNone,
+ "Prints out the current version number of the LLDB debugger." },
+ { LLDB_OPT_SET_3, true , "arch" , 'a', required_argument, 0, eArgTypeArchitecture,
+ "Tells the debugger to use the specified architecture when starting and running the program. <architecture> must "
+ "be one of the architectures for which the program was compiled." },
+ { LLDB_OPT_SET_3, true , "file" , 'f', required_argument, 0, eArgTypeFilename,
+ "Tells the debugger to use the file <filename> as the program to be debugged." },
+ { LLDB_OPT_SET_3, false, "core" , 'c', required_argument, 0, eArgTypeFilename,
+ "Tells the debugger to use the fullpath to <path> as the core file." },
+ { LLDB_OPT_SET_5, true , "attach-pid" , 'p', required_argument, 0, eArgTypePid,
+ "Tells the debugger to attach to a process with the given pid." },
+ { LLDB_OPT_SET_4, true , "attach-name" , 'n', required_argument, 0, eArgTypeProcessName,
+ "Tells the debugger to attach to a process with the given name." },
+ { LLDB_OPT_SET_4, true , "wait-for" , 'w', no_argument , 0, eArgTypeNone,
+ "Tells the debugger to wait for a process with the given pid or name to launch before attaching." },
+ { LLDB_3_TO_5, false, "source" , 's', required_argument, 0, eArgTypeFilename,
+ "Tells the debugger to read in and execute the lldb commands in the given file, after any file provided on the command line has been loaded." },
+ { LLDB_3_TO_5, false, "one-line" , 'o', required_argument, 0, eArgTypeNone,
+ "Tells the debugger to execute this one-line lldb command after any file provided on the command line has been loaded." },
+ { LLDB_3_TO_5, false, "source-before-file" , 'S', required_argument, 0, eArgTypeFilename,
+ "Tells the debugger to read in and execute the lldb commands in the given file, before any file provided on the command line has been loaded." },
+ { LLDB_3_TO_5, false, "one-line-before-file" , 'O', required_argument, 0, eArgTypeNone,
+ "Tells the debugger to execute this one-line lldb command before any file provided on the command line has been loaded." },
+ { LLDB_3_TO_5, false, "source-quietly" , 'Q', no_argument , 0, eArgTypeNone,
+ "Tells the debugger suppress output from commands provided in the -s, -S, -O and -o commands." },
+ { LLDB_3_TO_5, false, "editor" , 'e', no_argument , 0, eArgTypeNone,
+ "Tells the debugger to open source files using the host's \"external editor\" mechanism." },
+ { LLDB_3_TO_5, false, "no-lldbinit" , 'x', no_argument , 0, eArgTypeNone,
+ "Do not automatically parse any '.lldbinit' files." },
+ { LLDB_3_TO_5, false, "no-use-colors" , 'X', no_argument , 0, eArgTypeNone,
+ "Do not use colors." },
+ { LLDB_OPT_SET_6, true , "python-path" , 'P', no_argument , 0, eArgTypeNone,
+ "Prints out the path to the lldb.py file for this version of lldb." },
+ { LLDB_3_TO_5, false, "script-language", 'l', required_argument, 0, eArgTypeScriptLang,
+ "Tells the debugger to use the specified scripting language for user-defined scripts, rather than the default. "
+ "Valid scripting languages that can be specified include Python, Perl, Ruby and Tcl. Currently only the Python "
+ "extensions have been implemented." },
+ { LLDB_3_TO_5, false, "debug" , 'd', no_argument , 0, eArgTypeNone,
+ "Tells the debugger to print out extra information for debugging itself." },
+ { 0, false, NULL , 0 , 0 , 0, eArgTypeNone, NULL }
+};
+
+static const uint32_t last_option_set_with_args = 2;
+
+Driver::Driver () :
+ SBBroadcaster ("Driver"),
+ m_debugger (SBDebugger::Create(false)),
+ m_option_data ()
+{
+ // We want to be able to handle CTRL+D in the terminal to have it terminate
+ // certain input
+ m_debugger.SetCloseInputOnEOF (false);
+ g_debugger_name = (char *) m_debugger.GetInstanceName();
+ if (g_debugger_name == NULL)
+ g_debugger_name = (char *) "";
+ g_driver = this;
+}
+
+Driver::~Driver ()
+{
+ g_driver = NULL;
+ g_debugger_name = NULL;
+}
+
+
+// This function takes INDENT, which tells how many spaces to output at the front
+// of each line; TEXT, which is the text that is to be output. It outputs the
+// text, on multiple lines if necessary, to RESULT, with INDENT spaces at the
+// front of each line. It breaks lines on spaces, tabs or newlines, shortening
+// the line if necessary to not break in the middle of a word. It assumes that
+// each output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
+
+void
+OutputFormattedUsageText (FILE *out, int indent, const char *text, int output_max_columns)
+{
+ int len = strlen (text);
+ std::string text_string (text);
+
+ // Force indentation to be reasonable.
+ if (indent >= output_max_columns)
+ indent = 0;
+
+ // Will it all fit on one line?
+
+ if (len + indent < output_max_columns)
+ // Output as a single line
+ fprintf (out, "%*s%s\n", indent, "", text);
+ else
+ {
+ // We need to break it up into multiple lines.
+ int text_width = output_max_columns - indent - 1;
+ int start = 0;
+ int end = start;
+ int final_end = len;
+ int sub_len;
+
+ while (end < final_end)
+ {
+ // Dont start the 'text' on a space, since we're already outputting the indentation.
+ while ((start < final_end) && (text[start] == ' '))
+ start++;
+
+ end = start + text_width;
+ if (end > final_end)
+ end = final_end;
+ else
+ {
+ // If we're not at the end of the text, make sure we break the line on white space.
+ while (end > start
+ && text[end] != ' ' && text[end] != '\t' && text[end] != '\n')
+ end--;
+ }
+ sub_len = end - start;
+ std::string substring = text_string.substr (start, sub_len);
+ fprintf (out, "%*s%s\n", indent, "", substring.c_str());
+ start = end + 1;
+ }
+ }
+}
+
+void
+ShowUsage (FILE *out, OptionDefinition *option_table, Driver::OptionData data)
+{
+ uint32_t screen_width = 80;
+ uint32_t indent_level = 0;
+ const char *name = "lldb";
+
+ fprintf (out, "\nUsage:\n\n");
+
+ indent_level += 2;
+
+
+ // First, show each usage level set of options, e.g. <cmd> [options-for-level-0]
+ // <cmd> [options-for-level-1]
+ // etc.
+
+ uint32_t num_options;
+ uint32_t num_option_sets = 0;
+
+ for (num_options = 0; option_table[num_options].long_option != NULL; ++num_options)
+ {
+ uint32_t this_usage_mask = option_table[num_options].usage_mask;
+ if (this_usage_mask == LLDB_OPT_SET_ALL)
+ {
+ if (num_option_sets == 0)
+ num_option_sets = 1;
+ }
+ else
+ {
+ for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++)
+ {
+ if (this_usage_mask & 1 << j)
+ {
+ if (num_option_sets <= j)
+ num_option_sets = j + 1;
+ }
+ }
+ }
+ }
+
+ for (uint32_t opt_set = 0; opt_set < num_option_sets; opt_set++)
+ {
+ uint32_t opt_set_mask;
+
+ opt_set_mask = 1 << opt_set;
+
+ if (opt_set > 0)
+ fprintf (out, "\n");
+ fprintf (out, "%*s%s", indent_level, "", name);
+ bool is_help_line = false;
+
+ for (uint32_t i = 0; i < num_options; ++i)
+ {
+ if (option_table[i].usage_mask & opt_set_mask)
+ {
+ CommandArgumentType arg_type = option_table[i].argument_type;
+ const char *arg_name = SBCommandInterpreter::GetArgumentTypeAsCString (arg_type);
+ // This is a bit of a hack, but there's no way to say certain options don't have arguments yet...
+ // so we do it by hand here.
+ if (option_table[i].short_option == 'h')
+ is_help_line = true;
+
+ if (option_table[i].required)
+ {
+ if (option_table[i].option_has_arg == required_argument)
+ fprintf (out, " -%c <%s>", option_table[i].short_option, arg_name);
+ else if (option_table[i].option_has_arg == optional_argument)
+ fprintf (out, " -%c [<%s>]", option_table[i].short_option, arg_name);
+ else
+ fprintf (out, " -%c", option_table[i].short_option);
+ }
+ else
+ {
+ if (option_table[i].option_has_arg == required_argument)
+ fprintf (out, " [-%c <%s>]", option_table[i].short_option, arg_name);
+ else if (option_table[i].option_has_arg == optional_argument)
+ fprintf (out, " [-%c [<%s>]]", option_table[i].short_option, arg_name);
+ else
+ fprintf (out, " [-%c]", option_table[i].short_option);
+ }
+ }
+ }
+ if (!is_help_line && (opt_set <= last_option_set_with_args))
+ fprintf (out, " [[--] <PROGRAM-ARG-1> [<PROGRAM_ARG-2> ...]]");
+ }
+
+ fprintf (out, "\n\n");
+
+ // Now print out all the detailed information about the various options: long form, short form and help text:
+ // -- long_name <argument>
+ // - short <argument>
+ // help text
+
+ // This variable is used to keep track of which options' info we've printed out, because some options can be in
+ // more than one usage level, but we only want to print the long form of its information once.
+
+ Driver::OptionData::OptionSet options_seen;
+ Driver::OptionData::OptionSet::iterator pos;
+
+ indent_level += 5;
+
+ for (uint32_t i = 0; i < num_options; ++i)
+ {
+ // Only print this option if we haven't already seen it.
+ pos = options_seen.find (option_table[i].short_option);
+ if (pos == options_seen.end())
+ {
+ CommandArgumentType arg_type = option_table[i].argument_type;
+ const char *arg_name = SBCommandInterpreter::GetArgumentTypeAsCString (arg_type);
+
+ options_seen.insert (option_table[i].short_option);
+ fprintf (out, "%*s-%c ", indent_level, "", option_table[i].short_option);
+ if (arg_type != eArgTypeNone)
+ fprintf (out, "<%s>", arg_name);
+ fprintf (out, "\n");
+ fprintf (out, "%*s--%s ", indent_level, "", option_table[i].long_option);
+ if (arg_type != eArgTypeNone)
+ fprintf (out, "<%s>", arg_name);
+ fprintf (out, "\n");
+ indent_level += 5;
+ OutputFormattedUsageText (out, indent_level, option_table[i].usage_text, screen_width);
+ indent_level -= 5;
+ fprintf (out, "\n");
+ }
+ }
+
+ indent_level -= 5;
+
+ fprintf (out, "\n%*sNotes:\n",
+ indent_level, "");
+ indent_level += 5;
+
+ fprintf (out, "\n%*sMultiple \"-s\" and \"-o\" options can be provided. They will be processed from left to right in order, "
+ "\n%*swith the source files and commands interleaved. The same is true of the \"-S\" and \"-O\" options."
+ "\n%*sThe before file and after file sets can intermixed freely, the command parser will sort them out."
+ "\n%*sThe order of the file specifiers (\"-c\", \"-f\", etc.) is not significant in this regard.\n\n",
+ indent_level, "",
+ indent_level, "",
+ indent_level, "",
+ indent_level, "");
+
+ fprintf (out, "\n%*sIf you don't provide -f then the first argument will be the file to be debugged"
+ "\n%*swhich means that '%s -- <filename> [<ARG1> [<ARG2>]]' also works."
+ "\n%*sBut remember to end the options with \"--\" if any of your arguments have a \"-\" in them.\n\n",
+ indent_level, "",
+ indent_level, "",
+ name,
+ indent_level, "");
+}
+
+void
+BuildGetOptTable (OptionDefinition *expanded_option_table, std::vector<struct option> &getopt_table,
+ uint32_t num_options)
+{
+ if (num_options == 0)
+ return;
+
+ uint32_t i;
+ uint32_t j;
+ std::bitset<256> option_seen;
+
+ getopt_table.resize (num_options + 1);
+
+ for (i = 0, j = 0; i < num_options; ++i)
+ {
+ char short_opt = expanded_option_table[i].short_option;
+
+ if (option_seen.test(short_opt) == false)
+ {
+ getopt_table[j].name = expanded_option_table[i].long_option;
+ getopt_table[j].has_arg = expanded_option_table[i].option_has_arg;
+ getopt_table[j].flag = NULL;
+ getopt_table[j].val = expanded_option_table[i].short_option;
+ option_seen.set(short_opt);
+ ++j;
+ }
+ }
+
+ getopt_table[j].name = NULL;
+ getopt_table[j].has_arg = 0;
+ getopt_table[j].flag = NULL;
+ getopt_table[j].val = 0;
+
+}
+
+Driver::OptionData::OptionData () :
+ m_args(),
+ m_script_lang (lldb::eScriptLanguageDefault),
+ m_core_file (),
+ m_crash_log (),
+ m_initial_commands (),
+ m_after_file_commands (),
+ m_debug_mode (false),
+ m_source_quietly(false),
+ m_print_version (false),
+ m_print_python_path (false),
+ m_print_help (false),
+ m_wait_for(false),
+ m_process_name(),
+ m_process_pid(LLDB_INVALID_PROCESS_ID),
+ m_use_external_editor(false),
+ m_seen_options()
+{
+}
+
+Driver::OptionData::~OptionData ()
+{
+}
+
+void
+Driver::OptionData::Clear ()
+{
+ m_args.clear ();
+ m_script_lang = lldb::eScriptLanguageDefault;
+ m_initial_commands.clear ();
+ m_after_file_commands.clear ();
+ m_debug_mode = false;
+ m_source_quietly = false;
+ m_print_help = false;
+ m_print_version = false;
+ m_print_python_path = false;
+ m_use_external_editor = false;
+ m_wait_for = false;
+ m_process_name.erase();
+ m_process_pid = LLDB_INVALID_PROCESS_ID;
+}
+
+void
+Driver::OptionData::AddInitialCommand (const char *command, bool before_file, bool is_file, SBError &error)
+{
+ std::vector<std::pair<bool, std::string> > *command_set;
+ if (before_file)
+ command_set = &(m_initial_commands);
+ else
+ command_set = &(m_after_file_commands);
+
+ if (is_file)
+ {
+ SBFileSpec file(command);
+ if (file.Exists())
+ command_set->push_back (std::pair<bool, std::string> (true, optarg));
+ else if (file.ResolveExecutableLocation())
+ {
+ char final_path[PATH_MAX];
+ file.GetPath (final_path, sizeof(final_path));
+ std::string path_str (final_path);
+ command_set->push_back (std::pair<bool, std::string> (true, path_str));
+ }
+ else
+ error.SetErrorStringWithFormat("file specified in --source (-s) option doesn't exist: '%s'", optarg);
+ }
+ else
+ command_set->push_back (std::pair<bool, std::string> (false, optarg));
+}
+
+void
+Driver::ResetOptionValues ()
+{
+ m_option_data.Clear ();
+}
+
+const char *
+Driver::GetFilename() const
+{
+ if (m_option_data.m_args.empty())
+ return NULL;
+ return m_option_data.m_args.front().c_str();
+}
+
+const char *
+Driver::GetCrashLogFilename() const
+{
+ if (m_option_data.m_crash_log.empty())
+ return NULL;
+ return m_option_data.m_crash_log.c_str();
+}
+
+lldb::ScriptLanguage
+Driver::GetScriptLanguage() const
+{
+ return m_option_data.m_script_lang;
+}
+
+void
+Driver::ExecuteInitialCommands (bool before_file)
+{
+ size_t num_commands;
+ std::vector<std::pair<bool, std::string> > *command_set;
+ if (before_file)
+ command_set = &(m_option_data.m_initial_commands);
+ else
+ command_set = &(m_option_data.m_after_file_commands);
+
+ num_commands = command_set->size();
+ SBCommandReturnObject result;
+ bool old_async = GetDebugger().GetAsync();
+ GetDebugger().SetAsync(false);
+ for (size_t idx = 0; idx < num_commands; idx++)
+ {
+ bool is_file = (*command_set)[idx].first;
+ const char *command = (*command_set)[idx].second.c_str();
+ char command_string[PATH_MAX * 2];
+ const bool dump_stream_only_if_no_immediate = true;
+ const char *executed_command = command;
+ if (is_file)
+ {
+ ::snprintf (command_string, sizeof(command_string), "command source -s %i '%s'", m_option_data.m_source_quietly, command);
+ executed_command = command_string;
+ }
+
+ m_debugger.GetCommandInterpreter().HandleCommand (executed_command, result, false);
+ if (!m_option_data.m_source_quietly || result.Succeeded() == false)
+ {
+ const size_t output_size = result.GetOutputSize();
+ if (output_size > 0)
+ {
+ const char *cstr = result.GetOutput(dump_stream_only_if_no_immediate);
+ if (cstr)
+ printf ("%s", cstr);
+ }
+ const size_t error_size = result.GetErrorSize();
+ if (error_size > 0)
+ {
+ const char *cstr = result.GetError(dump_stream_only_if_no_immediate);
+ if (cstr)
+ printf ("%s", cstr);
+ }
+ }
+
+ if (result.Succeeded() == false)
+ {
+ const char *type = before_file ? "before file" : "after_file";
+ if (is_file)
+ ::fprintf(stderr, "Aborting %s command execution, command file: '%s' failed.\n", type, command);
+ else
+ ::fprintf(stderr, "Aborting %s command execution, command: '%s' failed.\n", type, command);
+ break;
+ }
+ result.Clear();
+ }
+ GetDebugger().SetAsync(old_async);
+}
+
+bool
+Driver::GetDebugMode() const
+{
+ return m_option_data.m_debug_mode;
+}
+
+
+// Check the arguments that were passed to this program to make sure they are valid and to get their
+// argument values (if any). Return a boolean value indicating whether or not to start up the full
+// debugger (i.e. the Command Interpreter) or not. Return FALSE if the arguments were invalid OR
+// if the user only wanted help or version information.
+
+SBError
+Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting)
+{
+ ResetOptionValues ();
+
+ SBCommandReturnObject result;
+
+ SBError error;
+ std::string option_string;
+ struct option *long_options = NULL;
+ std::vector<struct option> long_options_vector;
+ uint32_t num_options;
+
+ for (num_options = 0; g_options[num_options].long_option != NULL; ++num_options)
+ /* Do Nothing. */;
+
+ if (num_options == 0)
+ {
+ if (argc > 1)
+ error.SetErrorStringWithFormat ("invalid number of options");
+ return error;
+ }
+
+ BuildGetOptTable (g_options, long_options_vector, num_options);
+
+ if (long_options_vector.empty())
+ long_options = NULL;
+ else
+ long_options = &long_options_vector.front();
+
+ if (long_options == NULL)
+ {
+ error.SetErrorStringWithFormat ("invalid long options");
+ return error;
+ }
+
+ // Build the option_string argument for call to getopt_long_only.
+
+ for (int i = 0; long_options[i].name != NULL; ++i)
+ {
+ if (long_options[i].flag == NULL)
+ {
+ option_string.push_back ((char) long_options[i].val);
+ switch (long_options[i].has_arg)
+ {
+ default:
+ case no_argument:
+ break;
+ case required_argument:
+ option_string.push_back (':');
+ break;
+ case optional_argument:
+ option_string.append ("::");
+ break;
+ }
+ }
+ }
+
+ // This is kind of a pain, but since we make the debugger in the Driver's constructor, we can't
+ // know at that point whether we should read in init files yet. So we don't read them in in the
+ // Driver constructor, then set the flags back to "read them in" here, and then if we see the
+ // "-n" flag, we'll turn it off again. Finally we have to read them in by hand later in the
+ // main loop.
+
+ m_debugger.SkipLLDBInitFiles (false);
+ m_debugger.SkipAppInitFiles (false);
+
+ // Prepare for & make calls to getopt_long_only.
+#if __GLIBC__
+ optind = 0;
+#else
+ optreset = 1;
+ optind = 1;
+#endif
+ int val;
+ while (1)
+ {
+ int long_options_index = -1;
+ val = ::getopt_long_only (argc, const_cast<char **>(argv), option_string.c_str(), long_options, &long_options_index);
+
+ if (val == -1)
+ break;
+ else if (val == '?')
+ {
+ m_option_data.m_print_help = true;
+ error.SetErrorStringWithFormat ("unknown or ambiguous option");
+ break;
+ }
+ else if (val == 0)
+ continue;
+ else
+ {
+ m_option_data.m_seen_options.insert ((char) val);
+ if (long_options_index == -1)
+ {
+ for (int i = 0;
+ long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val;
+ ++i)
+ {
+ if (long_options[i].val == val)
+ {
+ long_options_index = i;
+ break;
+ }
+ }
+ }
+
+ if (long_options_index >= 0)
+ {
+ const int short_option = g_options[long_options_index].short_option;
+
+ switch (short_option)
+ {
+ case 'h':
+ m_option_data.m_print_help = true;
+ break;
+
+ case 'v':
+ m_option_data.m_print_version = true;
+ break;
+
+ case 'P':
+ m_option_data.m_print_python_path = true;
+ break;
+
+ case 'c':
+ {
+ SBFileSpec file(optarg);
+ if (file.Exists())
+ {
+ m_option_data.m_core_file = optarg;
+ }
+ else
+ error.SetErrorStringWithFormat("file specified in --core (-c) option doesn't exist: '%s'", optarg);
+ }
+ break;
+
+ case 'e':
+ m_option_data.m_use_external_editor = true;
+ break;
+
+ case 'x':
+ m_debugger.SkipLLDBInitFiles (true);
+ m_debugger.SkipAppInitFiles (true);
+ break;
+
+ case 'X':
+ m_debugger.SetUseColor (false);
+ break;
+
+ case 'f':
+ {
+ SBFileSpec file(optarg);
+ if (file.Exists())
+ {
+ m_option_data.m_args.push_back (optarg);
+ }
+ else if (file.ResolveExecutableLocation())
+ {
+ char path[PATH_MAX];
+ file.GetPath (path, sizeof(path));
+ m_option_data.m_args.push_back (path);
+ }
+ else
+ error.SetErrorStringWithFormat("file specified in --file (-f) option doesn't exist: '%s'", optarg);
+ }
+ break;
+
+ case 'a':
+ if (!m_debugger.SetDefaultArchitecture (optarg))
+ error.SetErrorStringWithFormat("invalid architecture in the -a or --arch option: '%s'", optarg);
+ break;
+
+ case 'l':
+ m_option_data.m_script_lang = m_debugger.GetScriptingLanguage (optarg);
+ break;
+
+ case 'd':
+ m_option_data.m_debug_mode = true;
+ break;
+
+ case 'Q':
+ m_option_data.m_source_quietly = true;
+ break;
+
+ case 'n':
+ m_option_data.m_process_name = optarg;
+ break;
+
+ case 'w':
+ m_option_data.m_wait_for = true;
+ break;
+
+ case 'p':
+ {
+ char *remainder;
+ m_option_data.m_process_pid = strtol (optarg, &remainder, 0);
+ if (remainder == optarg || *remainder != '\0')
+ error.SetErrorStringWithFormat ("Could not convert process PID: \"%s\" into a pid.",
+ optarg);
+ }
+ break;
+ case 's':
+ m_option_data.AddInitialCommand(optarg, false, true, error);
+ break;
+ case 'o':
+ m_option_data.AddInitialCommand(optarg, false, false, error);
+ break;
+ case 'S':
+ m_option_data.AddInitialCommand(optarg, true, true, error);
+ break;
+ case 'O':
+ m_option_data.AddInitialCommand(optarg, true, false, error);
+ break;
+ default:
+ m_option_data.m_print_help = true;
+ error.SetErrorStringWithFormat ("unrecognized option %c", short_option);
+ break;
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("invalid option with value %i", val);
+ }
+ if (error.Fail())
+ {
+ return error;
+ }
+ }
+ }
+
+ if (error.Fail() || m_option_data.m_print_help)
+ {
+ ShowUsage (out_fh, g_options, m_option_data);
+ exiting = true;
+ }
+ else if (m_option_data.m_print_version)
+ {
+ ::fprintf (out_fh, "%s\n", m_debugger.GetVersionString());
+ exiting = true;
+ }
+ else if (m_option_data.m_print_python_path)
+ {
+ SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
+ if (python_file_spec.IsValid())
+ {
+ char python_path[PATH_MAX];
+ size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);
+ if (num_chars < PATH_MAX)
+ {
+ ::fprintf (out_fh, "%s\n", python_path);
+ }
+ else
+ ::fprintf (out_fh, "<PATH TOO LONG>\n");
+ }
+ else
+ ::fprintf (out_fh, "<COULD NOT FIND PATH>\n");
+ exiting = true;
+ }
+ else if (m_option_data.m_process_name.empty() && m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // Any arguments that are left over after option parsing are for
+ // the program. If a file was specified with -f then the filename
+ // is already in the m_option_data.m_args array, and any remaining args
+ // are arguments for the inferior program. If no file was specified with
+ // -f, then what is left is the program name followed by any arguments.
+
+ // Skip any options we consumed with getopt_long_only
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0)
+ {
+ for (int arg_idx=0; arg_idx<argc; ++arg_idx)
+ {
+ const char *arg = argv[arg_idx];
+ if (arg)
+ m_option_data.m_args.push_back (arg);
+ }
+ }
+
+ }
+ else
+ {
+ // Skip any options we consumed with getopt_long_only
+ argc -= optind;
+ //argv += optind; // Commented out to keep static analyzer happy
+
+ if (argc > 0)
+ ::fprintf (out_fh, "Warning: program arguments are ignored when attaching.\n");
+ }
+
+ return error;
+}
+
+void
+Driver::MainLoop ()
+{
+ if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0)
+ {
+ g_old_stdin_termios_is_valid = true;
+ atexit (reset_stdin_termios);
+ }
+
+ ::setbuf (stdin, NULL);
+ ::setbuf (stdout, NULL);
+
+ m_debugger.SetErrorFileHandle (stderr, false);
+ m_debugger.SetOutputFileHandle (stdout, false);
+ m_debugger.SetInputFileHandle (stdin, true);
+
+ m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
+
+ struct winsize window_size;
+ if (isatty (STDIN_FILENO)
+ && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
+ {
+ if (window_size.ws_col > 0)
+ m_debugger.SetTerminalWidth (window_size.ws_col);
+ }
+
+ SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
+
+ // Before we handle any options from the command line, we parse the
+ // .lldbinit file in the user's home directory.
+ SBCommandReturnObject result;
+ sb_interpreter.SourceInitFileInHomeDirectory(result);
+ if (GetDebugMode())
+ {
+ result.PutError (m_debugger.GetErrorFileHandle());
+ result.PutOutput (m_debugger.GetOutputFileHandle());
+ }
+
+ // Now we handle options we got from the command line
+ // First source in the commands specified to be run before the file arguments are processed.
+ ExecuteInitialCommands(true);
+
+ // Was there a core file specified?
+ std::string core_file_spec("");
+ if (!m_option_data.m_core_file.empty())
+ core_file_spec.append("--core ").append(m_option_data.m_core_file);
+
+ char command_string[PATH_MAX * 2];
+ const size_t num_args = m_option_data.m_args.size();
+ if (num_args > 0)
+ {
+ char arch_name[64];
+ if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name)))
+ ::snprintf (command_string,
+ sizeof (command_string),
+ "target create --arch=%s %s \"%s\"",
+ arch_name,
+ core_file_spec.c_str(),
+ m_option_data.m_args[0].c_str());
+ else
+ ::snprintf (command_string,
+ sizeof(command_string),
+ "target create %s \"%s\"",
+ core_file_spec.c_str(),
+ m_option_data.m_args[0].c_str());
+
+ m_debugger.HandleCommand (command_string);
+
+ if (num_args > 1)
+ {
+ m_debugger.HandleCommand ("settings clear target.run-args");
+ char arg_cstr[1024];
+ for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
+ {
+ ::snprintf (arg_cstr,
+ sizeof(arg_cstr),
+ "settings append target.run-args \"%s\"",
+ m_option_data.m_args[arg_idx].c_str());
+ m_debugger.HandleCommand (arg_cstr);
+ }
+ }
+ }
+ else if (!core_file_spec.empty())
+ {
+ ::snprintf (command_string,
+ sizeof(command_string),
+ "target create %s",
+ core_file_spec.c_str());
+ m_debugger.HandleCommand (command_string);;
+ }
+ else if (!m_option_data.m_process_name.empty())
+ {
+ ::snprintf (command_string,
+ sizeof(command_string),
+ "process attach --name '%s'%s",
+ m_option_data.m_process_name.c_str(),
+ m_option_data.m_wait_for ? " --waitfor" : "");
+ m_debugger.HandleCommand (command_string);
+ }
+ else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid)
+ {
+ ::snprintf (command_string,
+ sizeof(command_string),
+ "process attach --pid %" PRIu64,
+ m_option_data.m_process_pid);
+ m_debugger.HandleCommand (command_string);
+ }
+
+ ExecuteInitialCommands(false);
+
+ // Now that all option parsing is done, we try and parse the .lldbinit
+ // file in the current working directory
+ sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result);
+ if (GetDebugMode())
+ {
+ result.PutError(m_debugger.GetErrorFileHandle());
+ result.PutOutput(m_debugger.GetOutputFileHandle());
+ }
+
+ bool handle_events = true;
+ bool spawn_thread = false;
+ m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
+
+ reset_stdin_termios();
+ fclose (stdin);
+
+ SBDebugger::Destroy (m_debugger);
+}
+
+void
+Driver::ResizeWindow (unsigned short col)
+{
+ GetDebugger().SetTerminalWidth (col);
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Setup *this driver so it works as pass through (child) driver for the MI
+// driver. Called by the parent (MI driver) driver.
+// This driver has setup code in two places. The original in MainLoop() and
+// in int main() (when MICONFIG_COMPILE_MIDRIVER_VERSION == 0) so that code can
+// remain as much near to the original code as possible. If MI driver is the main
+// driver (when MICONFIG_COMPILE_MIDRIVER_VERSION == 1) then this function is
+// used to set up the Driver to work with the MI driver.
+// Type: Method.
+// Args: vwErrMsg - (W) On failure current error discription.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool Driver::MISetup( CMIUtilString & vwErrMsg )
+{
+ bool bOk = MIstatus::success;
+
+ // Is *this driver a pass through driver to the MI driver
+ CMIDriverBase * pParent = GetDriversParent();
+ if( pParent == nullptr )
+ {
+ // No it is not.
+ // If MI is the main driver (which passes through to *this driver) then
+ // *this driver needs to be initialized after MI is initialize to have a valid
+ // pointer to the parent driver. *this is the parent's pass thru driver.
+ assert( pParent == nullptr );
+ return MIstatus::success; // Allow success for if Driver is the main driver
+ }
+
+ // MI driver may have streams it wants *this driver to use - still to be sorted
+ m_debugger.SetErrorFileHandle( pParent->GetStderr(), false ); // MI may redirect to its own stream
+ m_debugger.SetOutputFileHandle( pParent->GetStdout(), false ); // MI likely to NULL this
+ m_debugger.SetInputFileHandle( pParent->GetStdin(), false ); // MI could use this to feed input
+
+ // ToDo: Do I need this?
+ m_debugger.SetUseExternalEditor( m_option_data.m_use_external_editor );
+
+ // ToDo: Do I need this?
+ struct winsize window_size;
+ if( isatty( STDIN_FILENO ) && ::ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) == 0 )
+ {
+ if( window_size.ws_col > 0 )
+ m_debugger.SetTerminalWidth( window_size.ws_col );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize setup *this driver ready for use.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool Driver::DoInitialize( void )
+{
+ // Do nothing
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Unbind detach or release resources used by *this driver.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool Driver::DoShutdown( void )
+{
+ SBDebugger::Destroy( m_debugger );
+
+ // Is *this driver a pass through driver to the MI driver
+ CMIDriverBase * pParent = GetDriversParent();
+ if( pParent == nullptr )
+ {
+ // See DoInitialize().
+ assert( pParent == nullptr );
+ return MIstatus::success;
+ }
+
+ // Put stuff here when *this driver is a pass thru driver to the MI driver
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the name for *this driver.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString & - Driver name.
+// Throws: None.
+//--
+const CMIUtilString & Driver::GetName( void ) const
+{
+ static CMIUtilString name( "LLDB driver" );
+ return name;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve *this driver's last error condition.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString - Text description.
+// Throws: None.
+//--
+CMIUtilString Driver::GetError( void ) const
+{
+ // Do nothing - to implement
+ return CMIUtilString();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Call this function puts *this driver to work.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool Driver::DoMainLoop( void )
+{
+ MainLoop();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Call *this driver to resize the console window.
+// Type: Overridden.
+// Args: vTermWidth - (R) New window column size.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+void Driver::DoResizeWindow( const uint32_t vTermWidth )
+{
+ ResizeWindow( (unsigned short) vTermWidth );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Call *this driver to return it's debugger.
+// Type: Overridden.
+// Args: None.
+// Return: lldb::SBDebugger & - LLDB debugger object reference.
+// Throws: None.
+//--
+lldb::SBDebugger & Driver::GetTheDebugger( void )
+{
+ return GetDebugger();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Proxy function to allow the driver implementation to validate executable
+// command line arguments.
+// Type: Overrideable.
+// Args: argc - (R) An integer that contains the count of arguments that follow in
+// argv. The argc parameter is always greater than or equal to 1.
+// argv - (R) An array of null-terminated strings representing command-line
+// arguments entered by the user of the program. By convention,
+// argv[0] is the command with which the program is invoked.
+// vpStdOut - (R) Pointer to a standard output stream.
+// vwbExiting - (W) True = *this want to exit, Reasons: help, invalid arg(s),
+// version information only.
+// False = Continue to work, start debugger i.e. Command
+// interpreter.
+// Return: lldb::SBError - LLDB current error status.
+// Throws: None.
+//--
+lldb::SBError Driver::DoParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting )
+{
+ return ParseArgs( argc, argv, vpStdOut, vwbExiting );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: A client can ask if *this driver is GDB/MI compatible.
+// Type: Overridden.
+// Args: None.
+// Return: True - GBD/MI compatible LLDB front end.
+// False - Not GBD/MI compatible LLDB front end.
+// Throws: None.
+//--
+bool Driver::GetDriverIsGDBMICompatibleDriver( void ) const
+{
+ return false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: This function allows *this driver to call on another driver to perform work
+// should this driver not be able to handle the client data input.
+// SetDriverToFallThruTo() specifies the fall through to driver.
+// Check the error message if the function returns a failure.
+// Type: Overridden.
+// Args: vCmd - (R) Command instruction to interpret.
+// vwErrMsg - (W) Error description on command failing.
+// Return: MIstatus::success - Command succeeded.
+// MIstatus::failure - Command failed.
+// Throws: None.
+//--
+bool Driver::DoFallThruToAnotherDriver( const CMIUtilString & vCmd, CMIUtilString & vwErrMsg )
+{
+ bool bOk = MIstatus::success;
+ vwErrMsg.empty();
+
+ // ToDo: Implement do work on other driver after this driver said "Give up you try"
+ // This may nto be required if the feature to 'fall through' is not required
+ SBCommandReturnObject returnObj = lldb::SBCommandReturnObject();
+ SBCommandInterpreter cmdIntrp = m_debugger.GetCommandInterpreter();
+ const lldb::ReturnStatus cmdResult = cmdIntrp.HandleCommand( vCmd.c_str(), returnObj ); MIunused( cmdResult );
+ if( returnObj.Succeeded() == false )
+ {
+ bOk = MIstatus::failure;
+ vwErrMsg = returnObj.GetError();
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: This function allows *this driver to call functionality on the parent driver
+// ask for information for example.
+// Type: Overridden.
+// Args: vrOtherDriver - (R) Reference to another driver object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool Driver::SetDriverParent( const CMIDriverBase & vrOtherDriver )
+{
+ m_pDriverParent = const_cast< CMIDriverBase * >( &vrOtherDriver );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set a unique ID for *this driver. It cannot be empty.
+// Type: Overridden.
+// Args: vId - (R) Text description.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool Driver::SetId( const CMIUtilString & vId )
+{
+ if( vId.empty() )
+ {
+ // Invalid to have it empty
+ return MIstatus::failure;
+ }
+
+ m_strDriverId = vId;
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get the unique ID for *this driver.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString & - Text description.
+// Throws: None.
+//--
+const CMIUtilString & Driver::GetId( void ) const
+{
+ return m_strDriverId;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Create *this driver. Function contains functionality that needs to be called
+// prior to constructing the *this driver.
+// Type: Static method.
+// Args: None.
+// Return: Driver * - Ptr to the LLDB driver object.
+// Throws: None.
+//--
+Driver * Driver::CreateSelf( void )
+{
+ lldb::SBDebugger::Initialize();
+
+ Driver * pDriver = new Driver;
+ return pDriver;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the name for *this driver.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString - Driver name.
+// Throws: None.
+//--
+const CMIUtilString & Driver::GetDriverName( void ) const
+{
+ return GetName();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get the unique ID for *this driver.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString & - Text description.
+// Throws: None.
+//--
+const CMIUtilString & Driver::GetDriverId( void ) const
+{
+ return GetId();
+}
+
+#endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
+
diff --git a/tools/lldb-mi/Driver.h b/tools/lldb-mi/Driver.h
new file mode 100644
index 000000000000..39577c49bf05
--- /dev/null
+++ b/tools/lldb-mi/Driver.h
@@ -0,0 +1,163 @@
+//===-- Driver.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// In-house headers:
+#include "MICmnConfig.h"
+#if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
+
+#ifndef lldb_Driver_h_
+#define lldb_Driver_h_
+
+//#include "Platform.h" // IOR removed
+#include <lldb/Utility/PseudoTerminal.h>
+
+#include <set>
+#include <bitset>
+#include <string>
+#include <vector>
+
+#include <lldb/API/SBDefines.h>
+#include <lldb/API/SBBroadcaster.h>
+#include <lldb/API/SBDebugger.h>
+#include <lldb/API/SBError.h>
+#include "MIDriverMgr.h"
+#include "MIDriverBase.h"
+
+#define ASYNC true
+#define NO_ASYNC false
+
+class IOChannel;
+
+class Driver : public lldb::SBBroadcaster, public CMIDriverBase, public CMIDriverMgr::IDriver
+{
+// MI required code:
+// Static:
+public:
+ static Driver * CreateSelf( void );
+
+// Methods:
+public:
+ bool MISetup( CMIUtilString & vwErrMsg );
+
+// Overridden:
+public:
+ // From CMIDriverMgr::IDriver
+ virtual bool DoInitialize( void );
+ virtual bool DoShutdown( void );
+ virtual bool DoMainLoop( void );
+ virtual void DoResizeWindow( const uint32_t vWindowSizeWsCol );
+ virtual lldb::SBError DoParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting );
+ virtual CMIUtilString GetError( void ) const;
+ virtual const CMIUtilString & GetName( void ) const;
+ virtual lldb::SBDebugger & GetTheDebugger( void );
+ virtual bool GetDriverIsGDBMICompatibleDriver( void ) const;
+ virtual bool SetId( const CMIUtilString & vID );
+ virtual const CMIUtilString & GetId( void ) const;
+ // From CMIDriverBase
+ virtual bool DoFallThruToAnotherDriver( const CMIUtilString & vCmd, CMIUtilString & vwErrMsg );
+ virtual bool SetDriverParent( const CMIDriverBase & vrOtherDriver );
+ virtual const CMIUtilString & GetDriverName( void ) const;
+ virtual const CMIUtilString & GetDriverId( void ) const;
+
+// Original code:
+public:
+ Driver ();
+
+ virtual
+ ~Driver ();
+
+ void
+ MainLoop ();
+
+ lldb::SBError
+ ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &do_exit);
+
+ const char *
+ GetFilename() const;
+
+ const char *
+ GetCrashLogFilename() const;
+
+ const char *
+ GetArchName() const;
+
+ lldb::ScriptLanguage
+ GetScriptLanguage() const;
+
+ void
+ ExecuteInitialCommands (bool before_file);
+
+ bool
+ GetDebugMode() const;
+
+ class OptionData
+ {
+ public:
+ OptionData ();
+ ~OptionData ();
+
+ void
+ Clear();
+
+ void
+ AddInitialCommand (const char *command, bool before_file, bool is_file, lldb::SBError &error);
+
+ //static OptionDefinition m_cmd_option_table[];
+
+ std::vector<std::string> m_args;
+ lldb::ScriptLanguage m_script_lang;
+ std::string m_core_file;
+ std::string m_crash_log;
+ std::vector<std::pair<bool,std::string> > m_initial_commands;
+ std::vector<std::pair<bool,std::string> > m_after_file_commands;
+ bool m_debug_mode;
+ bool m_source_quietly;
+ bool m_print_version;
+ bool m_print_python_path;
+ bool m_print_help;
+ bool m_wait_for;
+ std::string m_process_name;
+ lldb::pid_t m_process_pid;
+ bool m_use_external_editor; // FIXME: When we have set/show variables we can remove this from here.
+ typedef std::set<char> OptionSet;
+ OptionSet m_seen_options;
+ };
+
+
+ static lldb::SBError
+ SetOptionValue (int option_idx,
+ const char *option_arg,
+ Driver::OptionData &data);
+
+
+ lldb::SBDebugger &
+ GetDebugger()
+ {
+ return m_debugger;
+ }
+
+ void
+ ResizeWindow (unsigned short col);
+
+private:
+ lldb::SBDebugger m_debugger;
+ OptionData m_option_data;
+
+ void
+ ResetOptionValues ();
+
+ void
+ ReadyForCommand ();
+};
+
+extern Driver * g_driver;
+
+#endif // lldb_Driver_h_
+
+#endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
diff --git a/tools/lldb-mi/MICmdArgContext.cpp b/tools/lldb-mi/MICmdArgContext.cpp
new file mode 100644
index 000000000000..b6efa9660c3b
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgContext.cpp
@@ -0,0 +1,255 @@
+//===-- MICmnArgContext.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnArgContext.cpp
+//
+// Overview: CMICmdArgContext implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdArgContext.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgContext constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgContext::CMICmdArgContext( void )
+: m_constCharSpace( ' ' )
+, m_constStrSpace( " " )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgContext constructor.
+// Type: Method.
+// Args: vrCmdLineArgsRaw - (R) The text description of the arguments options.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgContext::CMICmdArgContext( const CMIUtilString & vrCmdLineArgsRaw )
+: m_strCmdArgsAndOptions( vrCmdLineArgsRaw )
+, m_constCharSpace( ' ' )
+, m_constStrSpace( " " )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgContext destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgContext::~CMICmdArgContext( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the remainder of the command's argument options left to parse.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - Argument options text.
+// Throws: None.
+//--
+const CMIUtilString & CMICmdArgContext::GetArgsLeftToParse( void ) const
+{
+ return m_strCmdArgsAndOptions;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Ask if this arguments string has any arguments.
+// Type: Method.
+// Args: None.
+// Return: bool - True = Has one or more arguments present, false = no arguments.
+// Throws: None.
+//--
+bool CMICmdArgContext::IsEmpty( void ) const
+{
+ return m_strCmdArgsAndOptions.empty();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Remove the argument from the options text and any space after the argument
+// if applicable.
+// Type: Method.
+// Args: vArg - (R) The name of the argument.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgContext::RemoveArg( const CMIUtilString & vArg )
+{
+ if( vArg.empty() )
+ return MIstatus::success;
+
+ const MIuint nLen = vArg.length();
+ const MIuint nLenCntxt = m_strCmdArgsAndOptions.length();
+ if( nLen > nLenCntxt )
+ return MIstatus::failure;
+
+ MIuint nExtraSpace = 0;
+ MIint nPos = m_strCmdArgsAndOptions.find( vArg );
+ while( 1 )
+ {
+ if( nPos == (MIint) std::string::npos )
+ return MIstatus::success;
+
+ bool bPass1 = false;
+ if( nPos != 0 )
+ {
+ if( m_strCmdArgsAndOptions[ nPos - 1 ] == m_constCharSpace )
+ bPass1 = true;
+ }
+ else
+ bPass1 = true;
+
+ const MIuint nEnd = nPos + nLen;
+
+ if( bPass1 )
+ {
+ bool bPass2 = false;
+ if( nEnd < nLenCntxt )
+ {
+ if( m_strCmdArgsAndOptions[ nEnd ] == m_constCharSpace )
+ {
+ bPass2 = true;
+ nExtraSpace = 1;
+ }
+ }
+ else
+ bPass2 = true;
+
+ if( bPass2 )
+ break;
+ }
+
+ nPos = m_strCmdArgsAndOptions.find( vArg, nEnd );
+ }
+
+ const MIuint nPosEnd = nLen + nExtraSpace;
+ m_strCmdArgsAndOptions = m_strCmdArgsAndOptions.replace( nPos, nPosEnd, "" ).c_str();
+ m_strCmdArgsAndOptions = m_strCmdArgsAndOptions.Trim();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Remove the argument at the Nth word position along in the context string.
+// Any space after the argument is removed if applicable. A search is not
+// performed as there may be more than one vArg with the same 'name' in the
+// context string.
+// Type: Method.
+// Args: vArg - (R) The name of the argument.
+// nArgIndex - (R) The word count position to which to remove the vArg word.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgContext::RemoveArgAtPos( const CMIUtilString & vArg, const MIuint nArgIndex )
+{
+ MIuint nWordIndex = 0;
+ CMIUtilString strBuildContextUp;
+ const CMIUtilString::VecString_t vecWords( GetArgs() );
+ const bool bSpaceRequired( GetNumberArgsPresent() > 2 );
+
+ CMIUtilString::VecString_t::const_iterator it = vecWords.begin();
+ const CMIUtilString::VecString_t::const_iterator itEnd = vecWords.end();
+ while( it != itEnd )
+ {
+ const CMIUtilString & rWord( *it );
+ if( nWordIndex++ != nArgIndex )
+ {
+ // Single words
+ strBuildContextUp += rWord;
+ if( bSpaceRequired )
+ strBuildContextUp += m_constStrSpace;
+ }
+ else
+ {
+ // If quoted loose quoted text
+ if( ++it != itEnd )
+ {
+ CMIUtilString words = rWord;
+ while( vArg != words )
+ {
+ if( bSpaceRequired )
+ words += m_constStrSpace;
+ words += *it;
+ if( ++it == itEnd )
+ break;
+ }
+ if( it != itEnd )
+ --it;
+ }
+ }
+
+ // Next
+ if( it != itEnd )
+ ++it;
+ }
+
+ m_strCmdArgsAndOptions = strBuildContextUp;
+ m_strCmdArgsAndOptions = m_strCmdArgsAndOptions.Trim();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve number of arguments or options present in the command's option text.
+// Type: Method.
+// Args: None.
+// Return: MIuint - 0 to n arguments present.
+// Throws: None.
+//--
+MIuint CMICmdArgContext::GetNumberArgsPresent( void ) const
+{
+ CMIUtilString::VecString_t vecOptions;
+ return m_strCmdArgsAndOptions.SplitConsiderQuotes( m_constStrSpace, vecOptions );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve all the arguments or options remaining in *this context.
+// Type: Method.
+// Args: None.
+// Return: MIUtilString::VecString_t - List of args remaining.
+// Throws: None.
+//--
+CMIUtilString::VecString_t CMICmdArgContext::GetArgs( void ) const
+{
+ CMIUtilString::VecString_t vecOptions;
+ m_strCmdArgsAndOptions.SplitConsiderQuotes( m_constStrSpace, vecOptions );
+ return vecOptions;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Copy assignment operator.
+// Type: Method.
+// Args: vOther - (R) The variable to copy from.
+// Return: CMIUtilString & - this object.
+// Throws: None.
+//--
+CMICmdArgContext & CMICmdArgContext::operator= ( const CMICmdArgContext & vOther )
+{
+ if( this != &vOther )
+ {
+ m_strCmdArgsAndOptions = vOther.m_strCmdArgsAndOptions;
+ }
+
+ return *this;
+} \ No newline at end of file
diff --git a/tools/lldb-mi/MICmdArgContext.h b/tools/lldb-mi/MICmdArgContext.h
new file mode 100644
index 000000000000..699bac13e014
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgContext.h
@@ -0,0 +1,61 @@
+//===-- MICmdArgContext.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgContext.h
+//
+// Overview: CMICmdArgContext interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MIUtilString.h"
+
+//++ ============================================================================
+// Details: MI common code class. Command arguments and options string. Holds
+// the context string.
+// Based on the Interpreter pattern.
+// Gotchas: None.
+// Authors: Illya Rudkin 14/04/2014.
+// Changes: None.
+//--
+class CMICmdArgContext
+{
+// Methods:
+public:
+ /* ctor */ CMICmdArgContext( void );
+ /* ctor */ CMICmdArgContext( const CMIUtilString & vrCmdLineArgsRaw );
+ //
+ const CMIUtilString & GetArgsLeftToParse( void ) const;
+ MIuint GetNumberArgsPresent( void ) const;
+ CMIUtilString::VecString_t GetArgs( void ) const;
+ bool IsEmpty( void ) const;
+ bool RemoveArg( const CMIUtilString & vArg );
+ bool RemoveArgAtPos( const CMIUtilString & vArg, const MIuint nArgIndex );
+ //
+ CMICmdArgContext & operator= ( const CMICmdArgContext & vOther );
+
+// Overridden:
+public:
+ // From CMIUtilString
+ /* dtor */ virtual ~CMICmdArgContext( void );
+
+// Attributes:
+private:
+ CMIUtilString m_strCmdArgsAndOptions;
+ const MIchar m_constCharSpace;
+ const CMIUtilString m_constStrSpace;
+};
diff --git a/tools/lldb-mi/MICmdArgSet.cpp b/tools/lldb-mi/MICmdArgSet.cpp
new file mode 100644
index 000000000000..b0bee357cd6b
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgSet.cpp
@@ -0,0 +1,420 @@
+//===-- MICmdArgSet.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgSet.cpp
+//
+// Overview: CMICmdArgSet implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdArgSet.h"
+#include "MICmdArgValBase.h"
+#include "MICmnResources.h"
+#include "MICmnLog.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgSet constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgSet::CMICmdArgSet( void )
+: m_bIsArgsPresentButNotHandledByCmd( false )
+, m_constStrCommaSpc( ", " )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgSet destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgSet::~CMICmdArgSet( void )
+{
+ // Tidy up
+ Destroy();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources used by *this container object.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMICmdArgSet::Destroy( void )
+{
+ // Delete command argument objects
+ if( !m_setCmdArgs.empty() )
+ {
+ SetCmdArgs_t::iterator it = m_setCmdArgs.begin();
+ while( it != m_setCmdArgs.end() )
+ {
+ CMICmdArgValBase * pArg( *it );
+ delete pArg;
+
+ // Next
+ ++it;
+ }
+ m_setCmdArgs.clear();
+ }
+
+ m_setCmdArgsThatNotValid.clear();
+ m_setCmdArgsThatAreMissing.clear();
+ m_setCmdArgsNotHandledByCmd.clear();
+ m_setCmdArgsMissingInfo.clear();
+ m_bIsArgsPresentButNotHandledByCmd = false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the state flag indicating that the command set up ready to parse
+// command arguments or options found that one or more arguments was indeed
+// present but not handled. This is given as a warning in the MI log file.
+// Type: Method.
+// Args: None.
+// Return: bool - True = one or more args not handled, false = all args handled
+// Throws: None.
+//--
+bool CMICmdArgSet::IsArgsPresentButNotHandledByCmd( void ) const
+{
+ return m_bIsArgsPresentButNotHandledByCmd;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add the list of command's arguments to parse and validate another one.
+// Type: Method.
+// Args: vArg - (R) A command argument object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgSet::Add( const CMICmdArgValBase & vArg )
+{
+ CMICmdArgValBase * pArg = const_cast< CMICmdArgValBase * >( &vArg );
+ m_setCmdArgs.push_back( pArg );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: After validating an options line of text (the context) and there is a failure,
+// it is likely a mandatory command argument that is required is missing. This
+// function returns the argument that should be present.
+// Type: Method.
+// Args: None.
+// Return: SetCmdArgs_t & - Set of argument objects.
+// Throws: None.
+//--
+const CMICmdArgSet::SetCmdArgs_t & CMICmdArgSet::GetArgsThatAreMissing( void ) const
+{
+ return m_setCmdArgsThatAreMissing;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: After validating an options line of text (the context) and there is a failure,
+// it may be because one or more arguments were unable to extract a value. This
+// function returns the argument that were found to be invalid.
+// Type: Method.
+// Args: None.
+// Return: SetCmdArgs_t & - Set of argument objects.
+// Throws: None.
+//--
+const CMICmdArgSet::SetCmdArgs_t & CMICmdArgSet::GetArgsThatInvalid( void ) const
+{
+ return m_setCmdArgsThatNotValid;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The list of argument or option (objects) that were specified by the command
+// and so recognised when parsed but were not handled. Ideally the command
+// should handle all arguments and options presented to it. The command sends
+// warning to the MI log file to say that these options were not handled.
+// Used as one way to determine option that maybe should really be implemented
+// and not just ignored.
+// Type: Method.
+// Args: None.
+// Return: SetCmdArgs_t & - Set of argument objects.
+// Throws: None.
+//--
+const CMICmdArgSet::SetCmdArgs_t & CMICmdArgSet::GetArgsNotHandledByCmd( void ) const
+{
+ return m_setCmdArgsNotHandledByCmd;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Given a set of command argument objects parse the context option string to
+// find those argument and retrieve their value. If the function fails call
+// GetArgsThatAreMissing() to see which commands that were mandatory were
+// missing or failed to parse.
+// Type: Method.
+// Args: vStrMiCmd - (R) Command's name.
+// vCmdArgsText - (RW) A command's options or argument.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgSet::Validate( const CMIUtilString & vStrMiCmd, CMICmdArgContext & vwCmdArgsText )
+{
+ m_cmdArgContext = vwCmdArgsText;
+
+ // Iterate all the arguments or options required by a command
+ const MIuint nArgs = vwCmdArgsText.GetNumberArgsPresent();
+ MIuint nArgsMandatoryCnt = 0;
+ SetCmdArgs_t::const_iterator it = m_setCmdArgs.begin();
+ while( it != m_setCmdArgs.end() )
+ {
+ const CMICmdArgValBase * pArg( *it );
+ const CMIUtilString & rArgName( pArg->GetName() ); MIunused( rArgName );
+ if( pArg->GetIsMandatory() )
+ nArgsMandatoryCnt++;
+ if( !const_cast< CMICmdArgValBase * >( pArg )->Validate( vwCmdArgsText ) )
+ {
+ if( pArg->GetIsMandatory() && !pArg->GetFound() )
+ m_setCmdArgsThatAreMissing.push_back( const_cast< CMICmdArgValBase * >( pArg ) );
+ else if( pArg->GetFound() )
+ {
+ if( pArg->GetIsMissingOptions() )
+ m_setCmdArgsMissingInfo.push_back( const_cast< CMICmdArgValBase * >( pArg ) );
+ else if( !pArg->GetValid() )
+ m_setCmdArgsThatNotValid.push_back( const_cast< CMICmdArgValBase * >( pArg ) );
+ }
+ }
+ if( pArg->GetFound() && !pArg->GetIsHandledByCmd() )
+ {
+ m_bIsArgsPresentButNotHandledByCmd = true;
+ m_setCmdArgsNotHandledByCmd.push_back( const_cast< CMICmdArgValBase * >( pArg ) );
+ }
+
+ // Next
+ ++it;
+ }
+
+ // Check that one or more argument objects have any issues to report...
+
+ if( nArgs < nArgsMandatoryCnt )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CMD_ARGS_ERR_N_OPTIONS_REQUIRED ), nArgsMandatoryCnt ) );
+ return MIstatus::failure;
+ }
+
+ if( IsArgsPresentButNotHandledByCmd() )
+ WarningArgsNotHandledbyCmdLogFile( vStrMiCmd );
+
+ return ValidationFormErrorMessages( vwCmdArgsText );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Having validated the command's options text and failed for some reason form
+// the error message made up with the faults found.
+// Type: Method.
+// vCmdArgsText - (RW) A command's options or argument.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgSet::ValidationFormErrorMessages( const CMICmdArgContext & vwCmdArgsText )
+{
+ CMIUtilString strListMissing;
+ CMIUtilString strListInvalid;
+ CMIUtilString strListMissingInfo;
+ const bool bArgsMissing = (m_setCmdArgsThatAreMissing.size() > 0);
+ const bool bArgsInvalid = (m_setCmdArgsThatNotValid.size() > 0);
+ const bool bArgsMissingInfo = (m_setCmdArgsMissingInfo.size() > 0);
+ if( !(bArgsMissing || bArgsInvalid || bArgsMissingInfo) )
+ return MIstatus::success;
+ if( bArgsMissing )
+ {
+ MIuint i = 0;
+ SetCmdArgs_t::const_iterator it = m_setCmdArgsThatAreMissing.begin();
+ while( it != m_setCmdArgsThatAreMissing.end() )
+ {
+ if( i++ > 0 )
+ strListMissing += m_constStrCommaSpc;
+
+ const CMICmdArgValBase * pArg( *it );
+ strListMissing += pArg->GetName();
+
+ // Next
+ ++it;
+ }
+ }
+ if( bArgsInvalid )
+ {
+ MIuint i = 0;
+ SetCmdArgs_t::const_iterator it = m_setCmdArgsThatNotValid.begin();
+ while( it != m_setCmdArgsThatNotValid.end() )
+ {
+ if( i++ > 0 )
+ strListMissing += m_constStrCommaSpc;
+
+ const CMICmdArgValBase * pArg( *it );
+ strListInvalid += pArg->GetName();
+
+ // Next
+ ++it;
+ }
+ }
+ if( bArgsMissingInfo )
+ {
+ MIuint i = 0;
+ SetCmdArgs_t::const_iterator it = m_setCmdArgsMissingInfo.begin();
+ while( it != m_setCmdArgsMissingInfo.end() )
+ {
+ if( i++ > 0 )
+ strListMissingInfo += m_constStrCommaSpc;
+
+ const CMICmdArgValBase * pArg( *it );
+ strListMissingInfo += pArg->GetName();
+
+ // Next
+ ++it;
+ }
+ }
+
+ bool bHaveOneError = false;
+ CMIUtilString strError = MIRSRC( IDS_CMD_ARGS_ERR_PREFIX_MSG );
+ if( bArgsMissing && bArgsInvalid )
+ {
+ bHaveOneError = true;
+ strError += CMIUtilString::Format( MIRSRC( IDS_CMD_ARGS_ERR_VALIDATION_MAN_INVALID ), strListMissing.c_str(), strListInvalid.c_str() );
+ }
+ if( bArgsMissing )
+ {
+ if( bHaveOneError )
+ strError += ". ";
+ bHaveOneError = true;
+ strError += CMIUtilString::Format( MIRSRC( IDS_CMD_ARGS_ERR_VALIDATION_MANDATORY ), strListMissing.c_str() );
+ }
+ if( bArgsMissingInfo )
+ {
+ if( bHaveOneError )
+ strError += ". ";
+ bHaveOneError = true;
+ strError += CMIUtilString::Format( MIRSRC( IDS_CMD_ARGS_ERR_VALIDATION_MISSING_INF ), strListMissingInfo.c_str() );
+ }
+ if( bArgsInvalid )
+ {
+ if( bHaveOneError )
+ strError += ". ";
+ bHaveOneError = true;
+ strError += CMIUtilString::Format( MIRSRC( IDS_CMD_ARGS_ERR_VALIDATION_INVALID ), strListInvalid.c_str() );
+ }
+ if( !vwCmdArgsText.IsEmpty() )
+ {
+ if( bHaveOneError )
+ strError += ". ";
+ bHaveOneError = true;
+ strError += CMIUtilString::Format( MIRSRC( IDS_CMD_ARGS_ERR_CONTEXT_NOT_ALL_EATTEN ), vwCmdArgsText.GetArgsLeftToParse().c_str() );
+ }
+
+ if( bHaveOneError )
+ {
+ SetErrorDescription( strError );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Ask if the command's argument options text had any arguments.
+// Type: Method.
+// Args: None.
+// Return: bool - True = Has one or more arguments present, false = no arguments.
+// Throws: None.
+//--
+bool CMICmdArgSet::IsArgContextEmpty( void ) const
+{
+ return m_cmdArgContext.IsEmpty();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the number of arguments that are being used for the command.
+// Type: Method.
+// Args: None.
+// Return: MIuint - Argument count.
+// Throws: None.
+//--
+MIuint CMICmdArgSet::GetCount( void ) const
+{
+ return m_setCmdArgs.size();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Given a set of command argument objects retrieve the argument with the
+// specified name.
+// Type: Method.
+// Args: vpArg - (W) A pointer to a command's argument object.
+// Return: True - Argument found.
+// False - Argument not found.
+// Throws: None.
+//--
+bool CMICmdArgSet::GetArg( const CMIUtilString & vArgName, CMICmdArgValBase *& vpArg ) const
+{
+ bool bFound = false;
+ SetCmdArgs_t::const_iterator it = m_setCmdArgs.begin();
+ while( it != m_setCmdArgs.end() )
+ {
+ CMICmdArgValBase * pArg( *it );
+ if( pArg->GetName() == vArgName )
+ {
+ bFound = true;
+ vpArg = pArg;
+ break;
+ }
+
+ // Next
+ ++it;
+ }
+
+ return bFound;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Write a warning message to the MI Log file about the command's arguments or
+// options that were found present but not handled.
+// Type: Method.
+// Args: vrCmdName - (R) The command's name.
+// Return: None.
+// Throws: None.
+//--
+void CMICmdArgSet::WarningArgsNotHandledbyCmdLogFile( const CMIUtilString & vrCmdName )
+{
+#if MICONFIG_GIVE_WARNING_CMD_ARGS_NOT_HANDLED
+
+ CMIUtilString strArgsNotHandled;
+ const CMICmdArgSet::SetCmdArgs_t & rSetArgs = GetArgsNotHandledByCmd();
+ MIuint nCnt = 0;
+ CMICmdArgSet::SetCmdArgs_t::const_iterator it = rSetArgs.begin();
+ while( it != rSetArgs.end() )
+ {
+ if( nCnt++ > 0 )
+ strArgsNotHandled += m_constStrCommaSpc;
+ const CMICmdArgValBase * pArg = *it;
+ strArgsNotHandled += pArg->GetName();
+
+ // Next
+ ++it;
+ }
+
+ const CMIUtilString strWarningMsg( CMIUtilString::Format( MIRSRC( IDS_CMD_WRN_ARGS_NOT_HANDLED ), vrCmdName.c_str(), strArgsNotHandled.c_str() ) );
+ m_pLog->WriteLog( strWarningMsg );
+
+#endif // MICONFIG_GIVE_WARNING_CMD_ARGS_NOT_HANDLED
+}
diff --git a/tools/lldb-mi/MICmdArgSet.h b/tools/lldb-mi/MICmdArgSet.h
new file mode 100644
index 000000000000..5f8f5049d9af
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgSet.h
@@ -0,0 +1,109 @@
+//===-- MICmdArgSet.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgSet.h
+//
+// Overview: CMICmdArgSet interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <vector>
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MICmdArgContext.h"
+
+// Declarations:
+class CMICmdArgValBase;
+
+//++ ============================================================================
+// Details: MI common code class. Command arguments container class.
+// A command may have one or more arguments of which some may be optional.
+// *this class contains a list of the command's arguments which are
+// validates against the commands argument options string (context string).
+// Each argument tries to extract the value it is looking for.
+// Argument objects added to *this container are owned by this container
+// and are deleted when this container goes out of scope. Allocate argument
+// objects on the heap.
+// It is assummed the arguments to be parsed are read from left to right in
+// order. The order added to *this container is the order they will parsed.
+// Gotchas: None.
+// Authors: Illya Rudkin 14/04/2014.
+// Changes: None.
+//--
+class CMICmdArgSet : public CMICmnBase
+{
+// Classes:
+public:
+ //++
+ // Description: ArgSet's interface for command arguments to implement.
+ //--
+ class IArg
+ {
+ public:
+ virtual bool GetFound( void ) const = 0;
+ virtual bool GetIsHandledByCmd( void ) const = 0;
+ virtual bool GetIsMandatory( void ) const = 0;
+ virtual bool GetIsMissingOptions( void ) const = 0;
+ virtual const CMIUtilString & GetName( void ) const = 0;
+ virtual bool GetValid( void ) const = 0;
+ virtual bool Validate( CMICmdArgContext & vwArgContext ) = 0;
+
+ /* dtor */ virtual ~IArg( void ) {};
+ };
+
+// Typedefs:
+public:
+ typedef std::vector< CMICmdArgValBase * > SetCmdArgs_t;
+
+// Methods:
+public:
+ /* ctor */ CMICmdArgSet( void );
+
+ bool Add( const CMICmdArgValBase & vArg );
+ bool GetArg( const CMIUtilString & vArgName, CMICmdArgValBase *& vpArg ) const;
+ const SetCmdArgs_t & GetArgsThatAreMissing( void ) const;
+ const SetCmdArgs_t & GetArgsThatInvalid( void ) const;
+ MIuint GetCount( void ) const;
+ bool IsArgContextEmpty( void ) const;
+ bool IsArgsPresentButNotHandledByCmd( void ) const;
+ void WarningArgsNotHandledbyCmdLogFile( const CMIUtilString & vrCmdName );
+ bool Validate( const CMIUtilString & vStrMiCmd, CMICmdArgContext & vwCmdArgsText );
+
+// Overrideable:
+public:
+ /* dtor */ virtual ~CMICmdArgSet( void );
+
+// Methods:
+private:
+ const SetCmdArgs_t & GetArgsNotHandledByCmd( void ) const;
+ void Destroy( void ); // Release resources used by *this object
+ bool ValidationFormErrorMessages( const CMICmdArgContext & vwCmdArgsText );
+
+// Attributes:
+private:
+ bool m_bIsArgsPresentButNotHandledByCmd; // True = The driver's client presented the command with options recognised but not handled by a command, false = all args handled
+ SetCmdArgs_t m_setCmdArgs; // The set of arguments that are that the command is expecting to find in the options string
+ SetCmdArgs_t m_setCmdArgsThatAreMissing; // The set of arguments that are required by the command but are missing
+ SetCmdArgs_t m_setCmdArgsThatNotValid; // The set of arguments found in the text but for some reason unable to extract a value
+ SetCmdArgs_t m_setCmdArgsNotHandledByCmd; // The set of arguments specified by the command which were present to the command but not handled
+ SetCmdArgs_t m_setCmdArgsMissingInfo; // The set of arguments that were present but were found to be missing additional information i.e. --thread 3 but 3 is missing
+ CMICmdArgContext m_cmdArgContext; // Copy of the command's argument options text before validate takes place (empties it of content)
+ const CMIUtilString m_constStrCommaSpc;
+};
+
diff --git a/tools/lldb-mi/MICmdArgValBase.cpp b/tools/lldb-mi/MICmdArgValBase.cpp
new file mode 100644
index 000000000000..ceab1a494865
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValBase.cpp
@@ -0,0 +1,171 @@
+//===-- MICmdArgValBase.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValBase.cpp
+//
+// Overview: CMICmdArgValBase implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdArgValBase.h"
+#include "MIUtilString.h"
+#include "MICmdArgContext.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValBase constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValBase::CMICmdArgValBase( void )
+: m_bFound( false )
+, m_bValid( false )
+, m_bMandatory( false )
+, m_bHandled( false )
+, m_bIsMissingOptions( false )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValBase constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// vbHandleByCmd - (R) True = Command processes *this option, false = not handled.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValBase::CMICmdArgValBase( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd )
+: m_bFound( false )
+, m_bValid( false )
+, m_bMandatory( vbMandatory )
+, m_strArgName( vrArgName )
+, m_bHandled( vbHandleByCmd )
+, m_bIsMissingOptions( false )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValBase destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValBase::~CMICmdArgValBase( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the state flag of whether the argument is handled by the command or
+// not.
+// Type: Method.
+// Args: None.
+// Return: True - Command needs more information.
+// False - All information is present as expected.
+// Throws: None.
+//--
+bool CMICmdArgValBase::GetIsMissingOptions( void ) const
+{
+ return m_bIsMissingOptions;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the state flag of whether the argument is handled by the command or
+// not.
+// Type: Method.
+// Args: None.
+// Return: True - Command handles *this argument or option.
+// False - Not handled (argument specified but ignored).
+// Throws: None.
+//--
+bool CMICmdArgValBase::GetIsHandledByCmd( void ) const
+{
+ return m_bHandled;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the name of *this argument.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - Return the text name.
+// Throws: None.
+//--
+const CMIUtilString & CMICmdArgValBase::GetName( void ) const
+{
+ return m_strArgName;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the state flag of whether the argument was found in the command's
+// argument / options string.
+// Type: Method.
+// Args: None.
+// Return: True - Argument found.
+// False - Argument not found.
+// Throws: None.
+//--
+bool CMICmdArgValBase::GetFound( void ) const
+{
+ return m_bFound;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the state flag indicating whether the value was obtained from the
+// text arguments string and is valid.
+// Type: Method.
+// Args: None.
+// Return: True - Argument valid.
+// False - Argument not valid.
+// Throws: None.
+//--
+bool CMICmdArgValBase::GetValid( void ) const
+{
+ return m_bValid;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the state flag indicating whether *this argument is a mandatory
+// argument for the command or is optional to be present.
+// Type: Method.
+// Args: None.
+// Return: True - Mandatory.
+// False - Optional.
+// Throws: None.
+//--
+bool CMICmdArgValBase::GetIsMandatory( void ) const
+{
+ return m_bMandatory;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Parse the command's argument options string and try to extract the value *this
+// argument is looking for.
+// Type: Overrideable.
+// Args: vArgContext - (RW) The command's argument options string.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValBase::Validate( CMICmdArgContext & vwArgContext )
+{
+ MIunused( vwArgContext );
+
+ // Override to implement
+
+ return MIstatus::failure;
+} \ No newline at end of file
diff --git a/tools/lldb-mi/MICmdArgValBase.h b/tools/lldb-mi/MICmdArgValBase.h
new file mode 100644
index 000000000000..b367cb88ce29
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValBase.h
@@ -0,0 +1,157 @@
+//===-- Platform.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValBase.h
+//
+// Overview: CMICmdArgValBase interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MIUtilString.h"
+#include "MICmdArgSet.h"
+
+//++ ============================================================================
+// Details: MI common code class. Command argument base class. Arguments objects
+// needing specialization derived from *this class. An argument knows
+// what type of argument it is and how it is to interpret the options
+// (context) string to find and validate a matching argument and so
+// extract a value from it.
+// Argument objects are added to the CMICmdArgSet container object.
+// Once added the container they belong to that contain and will be
+// deleted when the container goes out of scope. Allocate argument
+// objects on the heap and pass in to the Add().
+// Note the code is written such that a command will produce an error
+// should it be presented with arguments or options it does not understand.
+// A command can recognise an option or argument then ignore if it
+// wishes (a warning is sent to the MI's Log file). This is so it is
+// hardwired to fail and catch arguments or options that presented by
+// different driver clients.
+// Based on the Interpreter pattern.
+// Gotchas: None.
+// Authors: Illya Rudkin 14/04/2014.
+// Changes: None.
+//--
+class CMICmdArgValBase : public CMICmdArgSet::IArg
+{
+// Methods:
+public:
+ /* ctor */ CMICmdArgValBase( void );
+ /* ctor */ CMICmdArgValBase( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd );
+
+// Overrideable:
+public:
+ /* dtor */ virtual ~CMICmdArgValBase( void );
+
+// Overridden:
+public:
+ // From CMICmdArgSet::IArg
+ virtual bool GetFound( void ) const;
+ virtual bool GetIsHandledByCmd( void ) const;
+ virtual bool GetIsMandatory( void ) const;
+ virtual bool GetIsMissingOptions( void ) const;
+ virtual const CMIUtilString & GetName( void ) const;
+ virtual bool GetValid( void ) const;
+ virtual bool Validate( CMICmdArgContext & vwArgContext );
+
+// Attributes:
+protected:
+ bool m_bFound; // True = yes found in arguments options text, false = not found
+ bool m_bValid; // True = yes argument parsed and valid, false = not valid
+ bool m_bMandatory; // True = yes arg must be present, false = optional argument
+ CMIUtilString m_strArgName;
+ bool m_bHandled; // True = Command processes *this option, false = not handled
+ bool m_bIsMissingOptions; // True = Command needs more information, false = ok
+};
+
+//++ ============================================================================
+// Details: MI common code class. Templated command argument base class.
+// Gotchas: None.
+// Authors: Illya Rudkin 14/04/2014.
+// Changes: None.
+//--
+template< class T >
+class CMICmdArgValBaseTemplate : public CMICmdArgValBase
+{
+// Methods:
+public:
+ /* ctor */ CMICmdArgValBaseTemplate( void );
+ /* ctor */ CMICmdArgValBaseTemplate( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd );
+ //
+ const T & GetValue( void ) const;
+
+// Overrideable:
+public:
+ /* dtor */ virtual ~CMICmdArgValBaseTemplate( void );
+
+// Attributes:
+protected:
+ T m_argValue;
+};
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValBaseTemplate constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+template< class T >
+CMICmdArgValBaseTemplate< T >::CMICmdArgValBaseTemplate( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValBaseTemplate constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// vbHandleByCmd - (R) True = Command processes *this option, false = not handled.
+// Return: None.
+// Throws: None.
+//--
+template< class T >
+CMICmdArgValBaseTemplate< T >::CMICmdArgValBaseTemplate( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd )
+: CMICmdArgValBase( vrArgName, vbMandatory, vbHandleByCmd )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValBaseTemplate destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+template< class T >
+CMICmdArgValBaseTemplate< T >::~CMICmdArgValBaseTemplate( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the value the argument parsed from the command's argument / options
+// text string.
+// Type: Method.
+// Args: None.
+// Return: Template type & - The arg value of *this object.
+// Throws: None.
+//--
+template< class T >
+const T & CMICmdArgValBaseTemplate< T >::GetValue( void ) const
+{
+ return m_argValue;
+}
diff --git a/tools/lldb-mi/MICmdArgValConsume.cpp b/tools/lldb-mi/MICmdArgValConsume.cpp
new file mode 100644
index 000000000000..72a57f870ad4
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValConsume.cpp
@@ -0,0 +1,119 @@
+//===-- MICmdArgValConsume.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValConsume.cpp
+//
+// Overview: CMICmdArgValConsume implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdArgValConsume.h"
+#include "MICmdArgContext.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValConsume constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValConsume::CMICmdArgValConsume( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValConsume constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValConsume::CMICmdArgValConsume( const CMIUtilString & vrArgName, const bool vbMandatory )
+: CMICmdArgValBaseTemplate( vrArgName, vbMandatory, true )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValConsume destructor.
+// Type: Overidden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValConsume::~CMICmdArgValConsume( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Parse the command's argument options string and try to extract the value *this
+// argument is looking for.
+// Type: Overridden.
+// Args: vwArgContext - (R) The command's argument options string.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValConsume::Validate( CMICmdArgContext & vwArgContext )
+{
+ if( vwArgContext.IsEmpty() )
+ return MIstatus::success;
+
+ if( vwArgContext.GetNumberArgsPresent() == 1 )
+ {
+ const CMIUtilString & rArg( vwArgContext.GetArgsLeftToParse() );
+ m_bFound = true;
+ m_bValid = true;
+ vwArgContext.RemoveArg( rArg );
+ return MIstatus::success;
+ }
+
+ // In reality there are more than one option, if so the file option
+ // is the last one (don't handle that here - find the best looking one)
+ const CMIUtilString::VecString_t vecOptions( vwArgContext.GetArgs() );
+ CMIUtilString::VecString_t::const_iterator it = vecOptions.begin();
+ while( it != vecOptions.end() )
+ {
+ const CMIUtilString & rTxt( *it );
+ m_bFound = true;
+
+ if( vwArgContext.RemoveArg( rTxt ) )
+ {
+ m_bValid = true;
+ return MIstatus::success;
+ }
+ else
+ return MIstatus::success;
+
+ // Next
+ ++it;
+ }
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Nothing to examine as we just want to consume the argument or option (ignore
+// it).
+// Type: Method.
+// Args: None.
+// Return: bool - True = yes ok, false = not ok.
+// Throws: None.
+//--
+bool CMICmdArgValConsume::IsOk( void ) const
+{
+ return true;
+}
diff --git a/tools/lldb-mi/MICmdArgValConsume.h b/tools/lldb-mi/MICmdArgValConsume.h
new file mode 100644
index 000000000000..a113d89458f3
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValConsume.h
@@ -0,0 +1,63 @@
+//===-- MICmdArgValConsume.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValConsume.h
+//
+// Overview: CMICmdArgValConsume interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdArgValBase.h"
+
+// Declarations:
+class CMICmdArgContext;
+
+//++ ============================================================================
+// Details: MI common code class. Command argument class. Arguments object
+// needing specialization derived from the CMICmdArgValBase class.
+// An argument knows what type of argument it is and how it is to
+// interpret the options (context) string to find and validate a matching
+// argument. This type having recognised its argument name just consumes
+// that argument or option (ignores it). This is the so the validation
+// process can then ask if all arguments or options have been recognised
+// other an error will occurred "argument not recognised". For example
+// this can be used to consume the "--" text which is not an argument in
+// itself. Normally the GetValue() function (in base class) would return
+// a value for the argument but is not the case for *this argument type
+// object.
+// Based on the Interpreter pattern.
+// Gotchas: None.
+// Authors: Illya Rudkin 20/05/2014.
+// Changes: None.
+//--
+class CMICmdArgValConsume : public CMICmdArgValBaseTemplate< CMIUtilString >
+{
+// Methods:
+public:
+ /* ctor */ CMICmdArgValConsume( void );
+ /* ctor */ CMICmdArgValConsume( const CMIUtilString & vrArgName, const bool vbMandatory );
+ //
+ bool IsOk( void ) const;
+
+// Overridden:
+public:
+ // From CMICmdArgValBase
+ /* dtor */ virtual ~CMICmdArgValConsume( void );
+ // From CMICmdArgSet::IArg
+ virtual bool Validate( CMICmdArgContext & vwArgContext );
+};
diff --git a/tools/lldb-mi/MICmdArgValFile.cpp b/tools/lldb-mi/MICmdArgValFile.cpp
new file mode 100644
index 000000000000..d5cc52b90b44
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValFile.cpp
@@ -0,0 +1,204 @@
+//===-- MICmdArgValFile.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValFile.cpp
+//
+// Overview: CMICmdArgValFile implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdArgValFile.h"
+#include "MICmdArgContext.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValFile constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValFile::CMICmdArgValFile( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValFile constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// vbHandleByCmd - (R) True = Command processes *this option, false = not handled.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValFile::CMICmdArgValFile( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd )
+: CMICmdArgValBaseTemplate( vrArgName, vbMandatory, vbHandleByCmd )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValFile destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValFile::~CMICmdArgValFile( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Parse the command's argument options string and try to extract the value *this
+// argument is looking for.
+// Type: Overridden.
+// Args: vwArgContext - (R) The command's argument options string.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValFile::Validate( CMICmdArgContext & vwArgContext )
+{
+ if( vwArgContext.IsEmpty() )
+ return MIstatus::success;
+
+ // The GDB/MI spec suggests there is only parameter
+
+ if( vwArgContext.GetNumberArgsPresent() == 1 )
+ {
+ const CMIUtilString & rFile( vwArgContext.GetArgsLeftToParse() );
+ if( IsFilePath( rFile ) )
+ {
+ m_bFound = true;
+ m_bValid = true;
+ m_argValue = rFile.Trim( '"' );
+ vwArgContext.RemoveArg( rFile );
+ return MIstatus::success;
+ }
+ else
+ return MIstatus::failure;
+ }
+
+ // In reality there are more than one option, if so the file option
+ // is the last one (don't handle that here - find the best looking one)
+ const CMIUtilString::VecString_t vecOptions( vwArgContext.GetArgs() );
+ CMIUtilString::VecString_t::const_iterator it = vecOptions.begin();
+ while( it != vecOptions.end() )
+ {
+ const CMIUtilString & rTxt( *it );
+ if( IsFilePath( rTxt ) )
+ {
+ m_bFound = true;
+
+ if( vwArgContext.RemoveArg( rTxt ) )
+ {
+ m_bValid = true;
+ m_argValue = rTxt.Trim( '"' );
+ return MIstatus::success;
+ }
+ else
+ return MIstatus::success;
+ }
+
+ // Next
+ ++it;
+ }
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Given some text extract the file name path from it. If a space is found in
+// path done return the path surrounded in quotes.
+// Type: Method.
+// Args: vrTxt - (R) The text to extract the file name path from.
+// Return: CMIUtilString - File name and or path.
+// Throws: None.
+//--
+CMIUtilString CMICmdArgValFile::GetFileNamePath( const CMIUtilString & vrTxt ) const
+{
+ CMIUtilString fileNamePath( vrTxt );
+
+ // Look for a space in the path
+ const MIchar cSpace = ' ';
+ const MIint nPos = fileNamePath.find( cSpace );
+ if( nPos != (MIint) std::string::npos )
+ fileNamePath = CMIUtilString::Format( "\"%s\"", fileNamePath.c_str() );
+
+ return fileNamePath;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the string and determine if it is a valid file name path.
+// Type: Method.
+// Args: vrFileNamePath - (R) File's name and directory path.
+// Return: bool - True = yes valid file path, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValFile::IsFilePath( const CMIUtilString & vrFileNamePath ) const
+{
+ if( vrFileNamePath.empty() )
+ return false;
+
+ const bool bHavePosSlash = (vrFileNamePath.find_first_of( "/" ) != std::string::npos);
+ const bool bHaveBckSlash = (vrFileNamePath.find_first_of( "\\" ) != std::string::npos);
+
+ // Look for --someLongOption
+ MIint nPos = vrFileNamePath.find_first_of( "--" );
+ const bool bLong = (nPos == 0);
+ if( bLong )
+ return false;
+
+ // Look for -f type short parameters
+ nPos = vrFileNamePath.find_first_of( "-" );
+ const bool bShort = (nPos == 0);
+ if( bShort )
+ return false;
+
+ // Look for i1 i2 i3....
+ nPos = vrFileNamePath.find_first_of( "i" );
+ const bool bFoundI1 = ((nPos == 0) && (::isdigit( vrFileNamePath[ 1 ] )) );
+ if( bFoundI1 )
+ return false;
+
+ const bool bValidChars = IsValidChars( vrFileNamePath );
+ if( bValidChars || bHavePosSlash || bHaveBckSlash )
+ return true;
+
+ return false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine if the path contains valid characters for a file path. Letters can be
+// either upper or lower case.
+// Type: Method.
+// Args: vrText - (R) The text data to examine.
+// Return: bool - True = yes valid, false = one or more chars is valid.
+// Throws: None.
+//--
+bool CMICmdArgValFile::IsValidChars( const CMIUtilString & vrText ) const
+{
+ const MIchar * pPtr = const_cast< MIchar * >( vrText.c_str() );
+ for( MIuint i = 0; i < vrText.length(); i++, pPtr++ )
+ {
+ const MIchar c = *pPtr;
+ if( ::isalnum( (int) c ) == 0 )
+ {
+ if( (c != '.') && (c != '-') && (c != '_') )
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/tools/lldb-mi/MICmdArgValFile.h b/tools/lldb-mi/MICmdArgValFile.h
new file mode 100644
index 000000000000..071727401454
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValFile.h
@@ -0,0 +1,61 @@
+//===-- MICmdArgValFile.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValFile.h
+//
+// Overview: CMICmdArgValFile interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdArgValBase.h"
+
+// Declarations:
+class CMICmdArgContext;
+
+//++ ============================================================================
+// Details: MI common code class. Command argument class. Arguments object
+// needing specialization derived from the CMICmdArgValBase class.
+// An argument knows what type of argument it is and how it is to
+// interpret the options (context) string to find and validate a matching
+// argument and so extract a value from it .
+// Based on the Interpreter pattern.
+// Gotchas: None.
+// Authors: Illya Rudkin 15/04/2014.
+// Changes: None.
+//--
+class CMICmdArgValFile : public CMICmdArgValBaseTemplate< CMIUtilString >
+{
+// Methods:
+public:
+ /* ctor */ CMICmdArgValFile( void );
+ /* ctor */ CMICmdArgValFile( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd );
+ //
+ bool IsFilePath( const CMIUtilString & vrFileNamePath ) const;
+ CMIUtilString GetFileNamePath( const CMIUtilString & vrTxt ) const;
+
+// Overridden:
+public:
+ // From CMICmdArgValBase
+ /* dtor */ virtual ~CMICmdArgValFile( void );
+ // From CMICmdArgSet::IArg
+ virtual bool Validate( CMICmdArgContext & vwArgContext );
+
+// Methods:
+private:
+ bool IsValidChars( const CMIUtilString & vrText ) const;
+};
diff --git a/tools/lldb-mi/MICmdArgValListBase.cpp b/tools/lldb-mi/MICmdArgValListBase.cpp
new file mode 100644
index 000000000000..37b729e42741
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValListBase.cpp
@@ -0,0 +1,221 @@
+//===-- MICmdArgValListBase.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValListBase.cpp
+//
+// Overview: CMICmdArgValListBase implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdArgValListBase.h"
+#include "MICmdArgContext.h"
+#include "MICmdArgValFile.h"
+#include "MICmdArgValNumber.h"
+#include "MICmdArgValOptionLong.h"
+#include "MICmdArgValOptionShort.h"
+#include "MICmdArgValString.h"
+#include "MICmdArgValThreadGrp.h"
+#include "MICmdArgValConsume.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValListBase constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValListBase::CMICmdArgValListBase( void )
+: m_eArgType( eArgValType_invalid )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValListBase constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// vbHandleByCmd - (R) True = Command processes *this option, false = not handled.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValListBase::CMICmdArgValListBase( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd )
+: CMICmdArgValBaseTemplate( vrArgName, vbMandatory, vbHandleByCmd )
+, m_eArgType( eArgValType_invalid )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValListBase constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// vbHandleByCmd - (R) True = Command processes *this option, false = not handled.
+// veType - (R) The type of argument to look for and create argument object of a certain type.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValListBase::CMICmdArgValListBase( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd, const ArgValType_e veType )
+: CMICmdArgValBaseTemplate( vrArgName, vbMandatory, vbHandleByCmd )
+, m_eArgType( veType )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValListBase destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValListBase::~CMICmdArgValListBase( void )
+{
+ // Tidy up
+ Destroy();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Tear down resources used by *this object.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMICmdArgValListBase::Destroy( void )
+{
+ // Tidy up
+ VecArgObjPtr_t::const_iterator it = m_argValue.begin();
+ while( it != m_argValue.end() )
+ {
+ CMICmdArgValBase * pArgObj = *it;
+ delete pArgObj;
+
+ // Next
+ ++it;
+ }
+ m_argValue.clear();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Create an CMICmdArgValBase derived object matching the type specified
+// and put the option or argument's value inside it.
+// Type: Method.
+// Args: vrTxt - (R) Text version the option or argument.
+// veType - (R) The type of argument or option object to create.
+// Return: CMICmdArgValBase * - Option object holding the value.
+// - NULL = Functional failed.
+// Throws: None.
+//--
+CMICmdArgValBase * CMICmdArgValListBase::CreationObj( const CMIUtilString & vrTxt, const ArgValType_e veType ) const
+{
+ CMICmdArgValBase * pOptionObj = nullptr;
+ switch( veType )
+ {
+ case eArgValType_File:
+ pOptionObj = new CMICmdArgValFile();
+ break;
+ case eArgValType_Consume:
+ pOptionObj = new CMICmdArgValConsume();
+ break;
+ case eArgValType_Number:
+ pOptionObj = new CMICmdArgValNumber();
+ break;
+ case eArgValType_OptionLong:
+ pOptionObj = new CMICmdArgValOptionLong();
+ break;
+ case eArgValType_OptionShort:
+ pOptionObj = new CMICmdArgValOptionShort();
+ break;
+ case eArgValType_String:
+ pOptionObj = new CMICmdArgValString();
+ break;
+ case eArgValType_StringQuoted:
+ pOptionObj = new CMICmdArgValString( true, false, false );
+ break;
+ case eArgValType_StringQuotedNumber:
+ pOptionObj = new CMICmdArgValString( true, true, false );
+ break;
+ case eArgValType_StringQuotedNumberPath:
+ pOptionObj = new CMICmdArgValString( true, true, true );
+ break;
+ case eArgValType_StringAnything:
+ pOptionObj = new CMICmdArgValString( true );
+ break;
+ case eArgValType_ThreadGrp:
+ pOptionObj = new CMICmdArgValThreadGrp();
+ break;
+ default:
+ return nullptr;
+ }
+
+ CMICmdArgContext argCntxt( vrTxt );
+ if( !pOptionObj->Validate( argCntxt ) )
+ return nullptr;
+
+ return pOptionObj;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Validate the option or argument is the correct type.
+// Type: Method.
+// Args: vrTxt - (R) Text version the option or argument.
+// veType - (R) The type of value to expect.
+// Return: bool - True = Yes expected type present, False = no.
+// Throws: None.
+//--
+bool CMICmdArgValListBase::IsExpectedCorrectType( const CMIUtilString & vrTxt, const ArgValType_e veType ) const
+{
+ bool bValid = false;
+ switch( veType )
+ {
+ case eArgValType_File:
+ bValid = CMICmdArgValFile().IsFilePath( vrTxt );
+ break;
+ case eArgValType_Consume:
+ bValid = CMICmdArgValConsume().IsOk();
+ break;
+ case eArgValType_Number:
+ bValid = CMICmdArgValNumber().IsArgNumber( vrTxt );
+ break;
+ case eArgValType_OptionLong:
+ bValid = CMICmdArgValOptionLong().IsArgLongOption( vrTxt );
+ break;
+ case eArgValType_OptionShort:
+ bValid = CMICmdArgValOptionShort().IsArgShortOption( vrTxt );
+ break;
+ case eArgValType_String:
+ bValid = CMICmdArgValString().IsStringArg( vrTxt );
+ break;
+ case eArgValType_StringQuoted:
+ bValid = CMICmdArgValString( true, false, false ).IsStringArg( vrTxt );
+ break;
+ case eArgValType_StringQuotedNumber:
+ bValid = CMICmdArgValString( true, true, false ).IsStringArg( vrTxt );
+ break;
+ case eArgValType_StringQuotedNumberPath:
+ bValid = CMICmdArgValString( true, true, true ).IsStringArg( vrTxt );
+ break;
+ case eArgValType_StringAnything:
+ bValid = CMICmdArgValString( true ).IsStringArg( vrTxt );
+ break;
+ case eArgValType_ThreadGrp:
+ bValid = CMICmdArgValThreadGrp().IsArgThreadGrp( vrTxt );
+ break;
+ default:
+ return false;
+ }
+
+ return bValid;
+}
diff --git a/tools/lldb-mi/MICmdArgValListBase.h b/tools/lldb-mi/MICmdArgValListBase.h
new file mode 100644
index 000000000000..2798efa19a48
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValListBase.h
@@ -0,0 +1,103 @@
+//===-- MICmdArgValListBase.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValListBase.h
+//
+// Overview: CMICmdArgValListBase interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <vector>
+
+// In-house headers:
+#include "MICmdArgValBase.h"
+
+// Declarations:
+class CMICmdArgContext;
+
+//++ ============================================================================
+// Details: MI common code class. Command argument with addition options class.
+// For example --recurse 1 2 4 [group ...]. Arguments object that
+// require a list of options associated with them derive from the
+// CMICmdArgValListBase class. Additional options are also extracted from
+// the command arguments text string.
+// An argument knows what type of argument it is and how it is to
+// interpret the options (context) string to find and validate a matching
+// options and so extract a values from it .
+// The CMICmdArgValBase objects are added to the derived argument class's
+// container. The option arguments belong to that derived class and will
+// be deleted that object goes out of scope.
+// Based on the Interpreter pattern.
+// Gotchas: None.
+// Authors: Illya Rudkin 16/04/2014.
+// Changes: None.
+//--
+class CMICmdArgValListBase : public CMICmdArgValBaseTemplate< std::vector< CMICmdArgValBase * > >
+{
+// Typedef:
+public:
+ typedef std::vector< CMICmdArgValBase * > VecArgObjPtr_t;
+
+// Enums:
+public:
+ //++ ---------------------------------------------------------------------------------
+ // Details: CMICmdArgValListBase needs to know what type of argument to look for in
+ // the command options text. It also needs to create argument objects of
+ // a specific type.
+ //--
+ enum ArgValType_e
+ {
+ eArgValType_File = 0,
+ eArgValType_Consume,
+ eArgValType_Number,
+ eArgValType_OptionLong,
+ eArgValType_OptionShort,
+ eArgValType_String,
+ eArgValType_StringQuoted,
+ eArgValType_StringQuotedNumber,
+ eArgValType_StringQuotedNumberPath,
+ eArgValType_StringAnything, // Accept any words for a string 'type' even if they look like --longOptions for example
+ eArgValType_ThreadGrp,
+ eArgValType_count, // Always the last one
+ eArgValType_invalid
+ };
+
+// Methods:
+public:
+ /* ctor */ CMICmdArgValListBase( void );
+ /* ctor */ CMICmdArgValListBase( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd );
+ /* ctor */ CMICmdArgValListBase( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd, const ArgValType_e veType );
+
+// Overridden:
+public:
+ // From CMICmdArgValBase
+ /* dtor */ virtual ~CMICmdArgValListBase( void );
+
+// Methods:
+protected:
+ bool IsExpectedCorrectType( const CMIUtilString & vrTxt, const ArgValType_e veType ) const;
+ CMICmdArgValBase * CreationObj( const CMIUtilString & vrTxt, const ArgValType_e veType ) const;
+
+// Attributes:
+protected:
+ ArgValType_e m_eArgType;
+
+// Methods:
+private:
+ void Destroy( void );
+};
diff --git a/tools/lldb-mi/MICmdArgValListOfN.cpp b/tools/lldb-mi/MICmdArgValListOfN.cpp
new file mode 100644
index 000000000000..246fa2c9445d
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValListOfN.cpp
@@ -0,0 +1,189 @@
+//===-- MICmdArgValListOfN.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValListOfN.cpp
+//
+// Overview: CMICmdArgValListOfN implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdArgValListOfN.h"
+#include "MICmdArgContext.h"
+#include "MICmdArgValFile.h"
+#include "MICmdArgValNumber.h"
+#include "MICmdArgValOptionLong.h"
+#include "MICmdArgValOptionShort.h"
+#include "MICmdArgValString.h"
+#include "MICmdArgValThreadGrp.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValListOfN constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValListOfN::CMICmdArgValListOfN( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValListOfN constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// vbHandleByCmd - (R) True = Command processes *this option, false = not handled.
+// veType - (R) The type of argument to look for and create argument object of a certain type.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValListOfN::CMICmdArgValListOfN( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd, const ArgValType_e veType )
+: CMICmdArgValListBase( vrArgName, vbMandatory, vbHandleByCmd, veType )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValListOfN destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValListOfN::~CMICmdArgValListOfN( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Parse the command's argument options string and try to extract the list of
+// arguments based on the argument object type to look for.
+// Type: Overridden.
+// Args: vwArgContext - (RW) The command's argument options string.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValListOfN::Validate( CMICmdArgContext & vwArgContext )
+{
+ if( m_eArgType >= eArgValType_count )
+ {
+ m_eArgType = eArgValType_invalid;
+ return MIstatus::failure;
+ }
+
+ if( vwArgContext.IsEmpty() )
+ return MIstatus::success;
+
+ const CMIUtilString & rArg( vwArgContext.GetArgsLeftToParse() );
+ if( IsListOfN( rArg ) && CreateList( rArg ) )
+ {
+ m_bFound = true;
+ m_bValid = true;
+ vwArgContext.RemoveArg( rArg );
+ return MIstatus::success;
+ }
+ else
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Create list of argument objects each holding a value extract from the command
+// options line.
+// Type: Method.
+// Args: vrTxt - (R) Some options text.
+// Return: bool - True = yes valid arg, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValListOfN::CreateList( const CMIUtilString & vrTxt )
+{
+ CMIUtilString::VecString_t vecOptions;
+ if( (m_eArgType == eArgValType_StringQuoted) ||
+ (m_eArgType == eArgValType_StringQuotedNumber) ||
+ (m_eArgType == eArgValType_StringQuotedNumberPath) ||
+ (m_eArgType == eArgValType_StringAnything) )
+ {
+ if( vrTxt.SplitConsiderQuotes( " ", vecOptions ) == 0 )
+ return MIstatus::failure;
+ }
+ else
+ if( vrTxt.Split( " ", vecOptions ) == 0 )
+ return MIstatus::failure;
+
+ CMIUtilString::VecString_t::const_iterator it = vecOptions.begin();
+ while( it != vecOptions.end() )
+ {
+ const CMIUtilString & rOption = *it;
+ CMICmdArgValBase * pOption = CreationObj( rOption, m_eArgType );
+ if( pOption != nullptr )
+ m_argValue.push_back( pOption );
+ else
+ return MIstatus::failure;
+
+ // Next
+ ++it;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the string and determine if it is a valid string type argument.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes valid arg, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValListOfN::IsListOfN( const CMIUtilString & vrTxt ) const
+{
+ CMIUtilString::VecString_t vecOptions;
+ if( (m_eArgType == eArgValType_StringQuoted) ||
+ (m_eArgType == eArgValType_StringQuotedNumber) ||
+ (m_eArgType == eArgValType_StringQuotedNumberPath) ||
+ (m_eArgType == eArgValType_StringAnything) )
+ {
+ if( vrTxt.SplitConsiderQuotes( " ", vecOptions ) == 0 )
+ return false;
+ }
+ else
+ if( vrTxt.Split( " ", vecOptions ) == 0 )
+ return false;
+
+ CMIUtilString::VecString_t::const_iterator it = vecOptions.begin();
+ while( it != vecOptions.end() )
+ {
+ const CMIUtilString & rOption = *it;
+ if( !IsExpectedCorrectType( rOption, m_eArgType ) )
+ break;
+
+ // Next
+ ++it;
+ }
+
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the list of CMICmdArgValBase derived option objects found following
+// *this long option argument. For example "list-thread-groups [ --recurse 1 ]"
+// where 1 is the list of expected option to follow.
+// Type: Method.
+// Args: None.
+// Return: CMICmdArgValListBase::VecArgObjPtr_t & - List of options.
+// Throws: None.
+//--
+const CMICmdArgValListBase::VecArgObjPtr_t & CMICmdArgValListOfN::GetExpectedOptions( void ) const
+{
+ return m_argValue;
+}
diff --git a/tools/lldb-mi/MICmdArgValListOfN.h b/tools/lldb-mi/MICmdArgValListOfN.h
new file mode 100644
index 000000000000..0fe5d2f4f831
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValListOfN.h
@@ -0,0 +1,98 @@
+//===-- MICmdArgValListOfN.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValListOfN.h
+//
+// Overview: CMICmdArgValListOfN interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <vector>
+
+// In-house headers:
+#include "MICmdArgValListBase.h"
+
+// Declarations:
+class CMICmdArgContext;
+
+//++ ============================================================================
+// Details: MI common code class. Command argument class. Arguments object
+// needing specialization derived from the CMICmdArgValBase class.
+// An argument knows what type of argument it is and how it is to
+// interpret the options (context) string to find and validate a matching
+// argument and so extract a value from it .
+// The CMICmdArgValBase objects added to *this ListOfN container belong
+// to this container and will be deleted when *this object goes out of
+// scope.
+// To parse arguments like 'thread-id ...' i.e. 1 10 12 13 ...
+// If vbMandatory argument is true it takes on the (...)+ specification
+// otherwise assumed to be (...)* specification.
+// Based on the Interpreter pattern.
+// Gotchas: None.
+// Authors: Illya Rudkin 16/04/2014.
+// Changes: None.
+//--
+class CMICmdArgValListOfN : public CMICmdArgValListBase
+{
+// Methods:
+public:
+ /* ctor */ CMICmdArgValListOfN( void );
+ /* ctor */ CMICmdArgValListOfN( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd, const ArgValType_e veType );
+ //
+ const VecArgObjPtr_t & GetExpectedOptions( void ) const;
+ template< class T1, typename T2 >
+ bool GetExpectedOption( T2 & vrwValue ) const;
+
+// Overridden:
+public:
+ // From CMICmdArgValBase
+ /* dtor */ virtual ~CMICmdArgValListOfN( void );
+ // From CMICmdArgSet::IArg
+ virtual bool Validate( CMICmdArgContext & vArgContext );
+
+// Methods:
+private:
+ bool IsListOfN( const CMIUtilString & vrTxt ) const;
+ bool CreateList( const CMIUtilString & vrTxt );
+};
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the first argument or option value from the list of 1 or more options
+// parsed from the command's options string.
+// Type: Template method.
+// Args: vrwValue - (W) Templated type return value.
+// T1 - The argument value's class type of the data hold in the list of options.
+// T2 - The type pf the variable which holds the value wanted.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed. List of object was empty.
+// Throws: None.
+//--
+template< class T1, typename T2 >
+bool CMICmdArgValListOfN::GetExpectedOption( T2 & vrwValue ) const
+{
+ const VecArgObjPtr_t & rVecOptions( GetExpectedOptions() );
+ VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin();
+ if( it2 != rVecOptions.end() )
+ {
+ const T1 * pOption = static_cast< T1 * >( *it2 );
+ vrwValue = pOption->GetValue();
+ return MIstatus::success;
+ }
+
+ return MIstatus::failure;
+}
diff --git a/tools/lldb-mi/MICmdArgValNumber.cpp b/tools/lldb-mi/MICmdArgValNumber.cpp
new file mode 100644
index 000000000000..18bdccdc9ac5
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValNumber.cpp
@@ -0,0 +1,167 @@
+//===-- MICmdArgValNumber.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValNumber.cpp
+//
+// Overview: CMICmdArgValNumber implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdArgValNumber.h"
+#include "MICmdArgContext.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValNumber constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValNumber::CMICmdArgValNumber( void )
+: m_nNumber( 0 )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValNumber constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// vbHandleByCmd - (R) True = Command processes *this option, false = not handled.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValNumber::CMICmdArgValNumber( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd )
+: CMICmdArgValBaseTemplate( vrArgName, vbMandatory, vbHandleByCmd )
+, m_nNumber( 0 )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValNumber destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValNumber::~CMICmdArgValNumber( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Parse the command's argument options string and try to extract the value *this
+// argument is looking for.
+// Type: Overridden.
+// Args: vwArgContext - (RW) The command's argument options string.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValNumber::Validate( CMICmdArgContext & vwArgContext )
+{
+ if( vwArgContext.IsEmpty() )
+ return MIstatus::success;
+
+ if( vwArgContext.GetNumberArgsPresent() == 1 )
+ {
+ const CMIUtilString & rArg( vwArgContext.GetArgsLeftToParse() );
+ if( IsArgNumber( rArg ) && ExtractNumber( rArg ) )
+ {
+ m_bFound = true;
+ m_bValid = true;
+ m_argValue = GetNumber();
+ vwArgContext.RemoveArg( rArg );
+ return MIstatus::success;
+ }
+ else
+ return MIstatus::failure;
+ }
+
+ // More than one option...
+ const CMIUtilString::VecString_t vecOptions( vwArgContext.GetArgs() );
+ CMIUtilString::VecString_t::const_iterator it = vecOptions.begin();
+ while( it != vecOptions.end() )
+ {
+ const CMIUtilString & rArg( *it );
+ if( IsArgNumber( rArg ) && ExtractNumber( rArg ) )
+ {
+ m_bFound = true;
+
+ if( vwArgContext.RemoveArg( rArg ) )
+ {
+ m_bValid = true;
+ m_argValue = GetNumber();
+ return MIstatus::success;
+ }
+ else
+ return MIstatus::failure;
+ }
+
+ // Next
+ ++it;
+ }
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the string and determine if it is a valid string type argument.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes valid arg, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValNumber::IsArgNumber( const CMIUtilString & vrTxt ) const
+{
+ // Look for --someLongOption
+ if( std::string::npos != vrTxt.find( "--" ) )
+ return false;
+
+ return vrTxt.IsNumber();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Extract the thread group number from the thread group argument.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValNumber::ExtractNumber( const CMIUtilString & vrTxt )
+{
+ MIint64 nNumber = 0;
+ bool bOk = vrTxt.ExtractNumber( nNumber );
+ if( bOk )
+ {
+ m_nNumber = static_cast< MIint >( nNumber );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the thread group ID found in the argument.
+// Type: Method.
+// Args: None.
+// Return: MIuint - Thread group ID.
+// Throws: None.
+//--
+MIint64 CMICmdArgValNumber::GetNumber( void ) const
+{
+ return m_nNumber;
+}
+
diff --git a/tools/lldb-mi/MICmdArgValNumber.h b/tools/lldb-mi/MICmdArgValNumber.h
new file mode 100644
index 000000000000..219b040a257d
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValNumber.h
@@ -0,0 +1,65 @@
+//===-- MICmdArgValNumber.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValNumber.h
+//
+// Overview: CMICmdArgValNumber interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdArgValBase.h"
+
+// Declarations:
+class CMICmdArgContext;
+
+//++ ============================================================================
+// Details: MI common code class. Command argument class. Arguments object
+// needing specialization derived from the CMICmdArgValBase class.
+// An argument knows what type of argument it is and how it is to
+// interpret the options (context) string to find and validate a matching
+// argument and so extract a value from it .
+// Based on the Interpreter pattern.
+// Gotchas: None.
+// Authors: Illya Rudkin 14/04/2014.
+// Changes: None.
+//--
+class CMICmdArgValNumber : public CMICmdArgValBaseTemplate< MIint64 >
+{
+// Methods:
+public:
+ /* ctor */ CMICmdArgValNumber( void );
+ /* ctor */ CMICmdArgValNumber( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd );
+ //
+ bool IsArgNumber( const CMIUtilString & vrTxt ) const;
+
+// Overridden:
+public:
+ // From CMICmdArgValBase
+ /* dtor */ virtual ~CMICmdArgValNumber( void );
+ // From CMICmdArgSet::IArg
+ virtual bool Validate( CMICmdArgContext & vwArgContext );
+
+// Methods:
+private:
+ bool ExtractNumber( const CMIUtilString & vrTxt );
+ MIint64 GetNumber( void ) const;
+
+// Attributes:
+private:
+ MIint64 m_nNumber;
+};
diff --git a/tools/lldb-mi/MICmdArgValOptionLong.cpp b/tools/lldb-mi/MICmdArgValOptionLong.cpp
new file mode 100644
index 000000000000..6c87984ba811
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValOptionLong.cpp
@@ -0,0 +1,319 @@
+//===-- MICmdArgValOptionLong.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValOptionLong.cpp
+//
+// Overview: CMICmdArgValOptionLong implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdArgValOptionLong.h"
+#include "MICmdArgContext.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValOptionLong constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValOptionLong::CMICmdArgValOptionLong( void )
+: m_nExpectingNOptions( 0 )
+, m_eExpectingOptionType( eArgValType_invalid )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValOptionLong constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// vbHandleByCmd - (R) True = Command processes *this option, false = not handled.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValOptionLong::CMICmdArgValOptionLong( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd )
+: CMICmdArgValListBase( vrArgName, vbMandatory, vbHandleByCmd )
+, m_nExpectingNOptions( 0 )
+, m_eExpectingOptionType( eArgValType_invalid )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValOptionLong constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// vbHandleByCmd - (R) True = Command processes *this option, false = not handled.
+// veType - (R) The type of argument to look for and create argument object of a certain type.
+// vnExpectingNOptions - (R) The number of options expected to read following *this argument.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValOptionLong::CMICmdArgValOptionLong( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd, const ArgValType_e veType, const MIuint vnExpectingNOptions )
+: CMICmdArgValListBase( vrArgName, vbMandatory, vbHandleByCmd )
+, m_nExpectingNOptions( vnExpectingNOptions )
+, m_eExpectingOptionType( veType )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValOptionLong destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValOptionLong::~CMICmdArgValOptionLong( void )
+{
+ // Tidy up
+ Destroy();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Tear down resources used by *this object.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMICmdArgValOptionLong::Destroy( void )
+{
+ // Tidy up
+ VecArgObjPtr_t::const_iterator it = m_vecArgsExpected.begin();
+ while( it != m_vecArgsExpected.end() )
+ {
+ CMICmdArgValBase * pOptionObj = *it;
+ delete pOptionObj;
+
+ // Next
+ ++it;
+ }
+ m_vecArgsExpected.clear();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Parse the command's argument options string and try to extract the long
+// argument *this argument type is looking for.
+// Type: Overridden.
+// Args: vwArgContext - (RW) The command's argument options string.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValOptionLong::Validate( CMICmdArgContext & vwArgContext )
+{
+ if( vwArgContext.IsEmpty() )
+ return MIstatus::success;
+
+ if( vwArgContext.GetNumberArgsPresent() == 1 )
+ {
+ const CMIUtilString & rArg( vwArgContext.GetArgsLeftToParse() );
+ if( IsArgLongOption( rArg ) && ArgNameMatch( rArg ) )
+ {
+ m_bFound = true;
+
+ if( !vwArgContext.RemoveArg( rArg ) )
+ return MIstatus::failure;
+
+ if( m_nExpectingNOptions == 0 )
+ {
+ m_bValid = true;
+ return MIstatus::success;
+ }
+
+ m_bIsMissingOptions = true;
+ return MIstatus::failure;
+ }
+ else
+ return MIstatus::failure;
+ }
+
+ // More than one option...
+ MIuint nArgIndex = 0;
+ const CMIUtilString::VecString_t vecOptions( vwArgContext.GetArgs() );
+ CMIUtilString::VecString_t::const_iterator it = vecOptions.begin();
+ while( it != vecOptions.end() )
+ {
+ const CMIUtilString & rArg( *it );
+ if( IsArgOptionCorrect( rArg ) && ArgNameMatch( rArg ) )
+ {
+ m_bFound = true;
+
+ if( !vwArgContext.RemoveArg( rArg ) )
+ return MIstatus::failure;
+
+ if( m_nExpectingNOptions != 0 )
+ {
+ if( ExtractExpectedOptions( vwArgContext, nArgIndex ) )
+ {
+ m_bValid = true;
+ return MIstatus::success;
+ }
+
+ m_bIsMissingOptions = true;
+ return MIstatus::failure;
+ }
+ else
+ {
+ m_bValid = true;
+ return MIstatus::success;
+ }
+ }
+
+ // Next
+ ++it;
+ ++nArgIndex;
+ }
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Parse the text following *this argument and extract the options the values of
+// CMICmdArgValListBase::m_eArgType forming argument objects for each of those
+// options extracted.
+// Type: Method.
+// Args: vrwTxt - (RW) The command's argument options string.
+// nArgIndex - (R) The Nth arg position in argument context from the left.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValOptionLong::ExtractExpectedOptions( CMICmdArgContext & vrwTxt, const MIuint nArgIndex )
+{
+ CMIUtilString::VecString_t vecOptions;
+ MIuint nOptionsPresent = 0;
+ if( (m_eExpectingOptionType != eArgValType_StringQuoted) &&
+ (m_eExpectingOptionType != eArgValType_StringQuotedNumber) &&
+ (m_eExpectingOptionType != eArgValType_StringQuotedNumberPath) )
+ nOptionsPresent = vrwTxt.GetArgsLeftToParse().Split( " ", vecOptions );
+ else
+ nOptionsPresent = vrwTxt.GetArgsLeftToParse().SplitConsiderQuotes( " ", vecOptions );
+ if( nOptionsPresent == 0 )
+ return MIstatus::failure;
+
+ MIuint nArgIndexCnt = 0;
+ MIuint nTypeCnt = 0;
+ MIuint nTypeCnt2 = 0;
+ MIuint nFoundNOptionsCnt = 0;
+ CMIUtilString::VecString_t::const_iterator it = vecOptions.begin();
+ while( it != vecOptions.end() )
+ {
+ // Move to the Nth argument position from left before do validation/checking
+ if( nArgIndexCnt++ == nArgIndex )
+ {
+ nTypeCnt++;
+ const CMIUtilString & rOption( *it );
+ if( IsExpectedCorrectType( rOption, m_eExpectingOptionType ) )
+ {
+ nTypeCnt2++;
+ CMICmdArgValBase * pOptionObj = CreationObj( rOption, m_eExpectingOptionType );
+ if( (pOptionObj != nullptr) && vrwTxt.RemoveArgAtPos( rOption, nArgIndex ) )
+ {
+ nFoundNOptionsCnt++;
+ m_vecArgsExpected.push_back( pOptionObj );
+ }
+ }
+
+ // Is the sequence 'options' of same type broken. Expecting the same type until the
+ // next argument.
+ if( nTypeCnt != nTypeCnt2 )
+ return MIstatus::failure;
+
+ if( nFoundNOptionsCnt == m_nExpectingNOptions )
+ return MIstatus::success;
+ }
+
+ // Next
+ ++it;
+ }
+ if( nFoundNOptionsCnt != m_nExpectingNOptions )
+ return MIstatus::failure;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the string and determine if it is a valid long type option argument.
+// Long type argument looks like --someLongOption.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes valid arg, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValOptionLong::IsArgLongOption( const CMIUtilString & vrTxt ) const
+{
+ const bool bHavePosSlash = (vrTxt.find_first_of( "/" ) != std::string::npos);
+ const bool bHaveBckSlash = (vrTxt.find_first_of( "\\" ) != std::string::npos);
+ if( bHavePosSlash || bHaveBckSlash )
+ return false;
+
+ const MIint nPos = vrTxt.find_first_of( "--" );
+ if( nPos != 0 )
+ return false;
+
+ if( vrTxt.length() < 3 )
+ return false;
+
+ const CMIUtilString strArg = vrTxt.substr( 2 ).c_str();
+ if( strArg.IsNumber() )
+ return false;
+
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the string and determine if it is a valid long type option argument.
+// Long type argument looks like --someLongOption.
+// Type: Overideable.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes valid arg, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValOptionLong::IsArgOptionCorrect( const CMIUtilString & vrTxt ) const
+{
+ return IsArgLongOption( vrTxt );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Does the argument name of the argument being parsed ATM match the name of
+// *this argument object.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes arg name matched, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValOptionLong::ArgNameMatch( const CMIUtilString & vrTxt ) const
+{
+ const CMIUtilString strArg = vrTxt.substr( 2 ).c_str();
+ return (strArg == GetName() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the list of CMICmdArgValBase derived option objects found following
+// *this long option argument. For example "list-thread-groups [ --recurse 1 ]"
+// where 1 is the list of expected option to follow.
+// Type: Method.
+// Args: None.
+// Return: CMICmdArgValListBase::VecArgObjPtr_t & - List of options.
+// Throws: None.
+//--
+const CMICmdArgValListBase::VecArgObjPtr_t & CMICmdArgValOptionLong::GetExpectedOptions( void ) const
+{
+ return m_vecArgsExpected;
+}
+
diff --git a/tools/lldb-mi/MICmdArgValOptionLong.h b/tools/lldb-mi/MICmdArgValOptionLong.h
new file mode 100644
index 000000000000..3baae416c93a
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValOptionLong.h
@@ -0,0 +1,109 @@
+//===-- MICmdArgValOptionLong.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValOptionLong.h
+//
+// Overview: CMICmdArgValOptionLong interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdArgValListBase.h"
+
+// Declarations:
+class CMICmdArgContext;
+class CMIUtilString;
+
+//++ ============================================================================
+// Details: MI common code class. Command argument class. Arguments object
+// needing specialization derived from the CMICmdArgValBase class.
+// An argument knows what type of argument it is and how it is to
+// interpret the options (context) string to find and validate a matching
+// argument and so extract a value from it.
+// If *this argument has expected options following it the option objects
+// created to hold each of those option's values belong to *this argument
+// object and so are deleted when *this object goes out of scope.
+// Based on the Interpreter pattern.
+// Gotchas: None.
+// Authors: Illya Rudkin 16/04/2014.
+// Changes: None.
+//--
+class CMICmdArgValOptionLong : public CMICmdArgValListBase
+{
+// Methods:
+public:
+ /* ctor */ CMICmdArgValOptionLong( void );
+ /* ctor */ CMICmdArgValOptionLong( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd );
+ /* ctor */ CMICmdArgValOptionLong( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd, const ArgValType_e veType, const MIuint vnExpectingNOptions );
+ //
+ bool IsArgLongOption( const CMIUtilString & vrTxt ) const;
+ const VecArgObjPtr_t & GetExpectedOptions( void ) const;
+ template< class T1, typename T2 >
+ bool GetExpectedOption( T2 & vrwValue ) const;
+
+// Overridden:
+public:
+ // From CMICmdArgValBase
+ /* dtor */ virtual ~CMICmdArgValOptionLong( void );
+ // From CMICmdArgSet::IArg
+ virtual bool Validate( CMICmdArgContext & vArgContext );
+
+// Methods:
+protected:
+ bool ExtractExpectedOptions( CMICmdArgContext & vrwTxt, const MIuint nArgIndex );
+
+// Overrideable:
+protected:
+ virtual bool IsArgOptionCorrect( const CMIUtilString & vrTxt ) const;
+ virtual bool ArgNameMatch( const CMIUtilString & vrTxt ) const;
+
+// Methods:
+private:
+ void Destroy( void );
+
+// Attributes:
+private:
+ MIuint m_nExpectingNOptions; // The number of options expected to read following *this argument
+ VecArgObjPtr_t m_vecArgsExpected; // The option objects holding the value extracted following *this argument
+ ArgValType_e m_eExpectingOptionType; // The type of options expected to read following *this argument
+};
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the first argument or option value from the list of 1 or more options
+// parsed from the command's options string.
+// Type: Template method.
+// Args: vrwValue - (W) Templated type return value.
+// T1 - The argument value's class type of the data hold in the list of options.
+// T2 - The type pf the variable which holds the value wanted.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed. List of object was empty.
+// Throws: None.
+//--
+template< class T1, typename T2 >
+bool CMICmdArgValOptionLong::GetExpectedOption( T2 & vrwValue ) const
+{
+ const VecArgObjPtr_t & rVecOptions( GetExpectedOptions() );
+ VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin();
+ if( it2 != rVecOptions.end() )
+ {
+ const T1 * pOption = static_cast< T1 * >( *it2 );
+ vrwValue = pOption->GetValue();
+ return MIstatus::success;
+ }
+
+ return MIstatus::failure;
+}
diff --git a/tools/lldb-mi/MICmdArgValOptionShort.cpp b/tools/lldb-mi/MICmdArgValOptionShort.cpp
new file mode 100644
index 000000000000..76adb7f11493
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValOptionShort.cpp
@@ -0,0 +1,128 @@
+//===-- MICmdArgValOptionShort.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValOptionShort.cpp
+//
+// Overview: CMICmdArgValOptionShort implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdArgValOptionShort.h"
+#include "MICmdArgContext.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValOptionShort constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValOptionShort::CMICmdArgValOptionShort( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValOptionShort constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// vbHandleByCmd - (R) True = Command processes *this option, false = not handled.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValOptionShort::CMICmdArgValOptionShort( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd )
+: CMICmdArgValOptionLong( vrArgName, vbMandatory, vbHandleByCmd )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValOptionLong constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// vbHandleByCmd - (R) True = Command processes *this option, false = not handled.
+// veType - (R) The type of argument to look for and create argument object of a certain type.
+// vnExpectingNOptions - (R) The number of options expected to read following *this argument.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValOptionShort::CMICmdArgValOptionShort( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd, const ArgValType_e veType, const MIuint vnExpectingNOptions )
+: CMICmdArgValOptionLong( vrArgName, vbMandatory, vbHandleByCmd, veType, vnExpectingNOptions )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValOptionShort destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValOptionShort::~CMICmdArgValOptionShort( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the string and determine if it is a valid short type option argument.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes valid arg, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValOptionShort::IsArgShortOption( const CMIUtilString & vrTxt ) const
+{
+ // Look for --someLongOption
+ MIint nPos = vrTxt.find( "--" );
+ if( nPos == 0 )
+ return false;
+
+ // Look for -f short option
+ nPos = vrTxt.find( "-" );
+ if( nPos != 0 )
+ return false;
+
+ if( vrTxt.length() > 2 )
+ return false;
+
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the string and determine if it is a valid short type option argument.
+// Long type argument looks like -f some short option.
+// Type: Overridden.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes valid arg, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValOptionShort::IsArgOptionCorrect( const CMIUtilString & vrTxt ) const
+{
+ return IsArgShortOption( vrTxt );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Does the argument name of the argument being parsed ATM match the name of
+// *this argument object.
+// Type: Overridden.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes arg name matched, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValOptionShort::ArgNameMatch( const CMIUtilString & vrTxt ) const
+{
+ const CMIUtilString strArg = vrTxt.substr( 1 ).c_str();
+ return (strArg == GetName() );
+}
diff --git a/tools/lldb-mi/MICmdArgValOptionShort.h b/tools/lldb-mi/MICmdArgValOptionShort.h
new file mode 100644
index 000000000000..7af038377123
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValOptionShort.h
@@ -0,0 +1,65 @@
+//===-- MICmdArgValOptionShort.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValOptionShort.h
+//
+// Overview: CMICmdArgValOptionShort interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdArgValOptionLong.h"
+
+// Declarations:
+class CMICmdArgContext;
+class CMIUtilString;
+
+//++ ============================================================================
+// Details: MI common code class. Command argument class. Arguments object
+// needing specialization derived from the CMICmdArgValOptionLong class.
+// An argument knows what type of argument it is and how it is to
+// interpret the options (context) string to find and validate a matching
+// argument and so extract a value from it.
+// If *this argument has expected options following it the option objects
+// created to hold each of those option's values belong to *this argument
+// object and so are deleted when *this object goes out of scope.
+// Based on the Interpreter pattern.
+// Gotchas: None.
+// Authors: Illya Rudkin 16/04/2014.
+// Changes: None.
+//--
+class CMICmdArgValOptionShort : public CMICmdArgValOptionLong
+{
+// Methods:
+public:
+ /* ctor */ CMICmdArgValOptionShort( void );
+ /* ctor */ CMICmdArgValOptionShort( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd );
+ /* ctor */ CMICmdArgValOptionShort( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd, const ArgValType_e veType, const MIuint vnExpectingNOptions );
+ //
+ bool IsArgShortOption( const CMIUtilString & vrTxt ) const;
+
+// Overridden:
+public:
+ // From CMICmdArgValBase
+ /* dtor */ virtual ~CMICmdArgValOptionShort( void );
+
+// Overridden:
+private:
+ // From CMICmdArgValOptionLong
+ virtual bool IsArgOptionCorrect( const CMIUtilString & vrTxt ) const;
+ virtual bool ArgNameMatch( const CMIUtilString & vrTxt ) const;
+};
diff --git a/tools/lldb-mi/MICmdArgValString.cpp b/tools/lldb-mi/MICmdArgValString.cpp
new file mode 100644
index 000000000000..06818b1dc571
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValString.cpp
@@ -0,0 +1,502 @@
+//===-- MICmdArgValString.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValString.cpp
+//
+// Overview: CMICmdArgValString implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdArgValString.h"
+#include "MICmdArgContext.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValString constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValString::CMICmdArgValString( void )
+: m_bHandleQuotedString( false )
+, m_bAcceptNumbers( false )
+, m_bHandleDirPaths( false )
+, m_bHandleAnything( false )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValString constructor.
+// Type: Method.
+// Args: vbAnything - (R) True = Parse a string and accept anything, false = do not accept anything.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValString::CMICmdArgValString( const bool vbAnything )
+: m_bHandleQuotedString( false )
+, m_bAcceptNumbers( false )
+, m_bHandleDirPaths( false )
+, m_bHandleAnything( vbAnything )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValString constructor.
+// Type: Method.
+// Args: vbHandleQuotes - (R) True = Parse a string surrounded by quotes spaces are not delimitors, false = only text up to next delimiting space character.
+// vbAcceptNumbers - (R) True = Parse a string and accept as a number if number, false = numbers not recognised as string types.
+// vbHandleDirPaths - (R) True = Parse a string and accept as a file path if a path, false = file paths are not recognised as string types.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValString::CMICmdArgValString( const bool vbHandleQuotes, const bool vbAcceptNumbers, const bool vbHandleDirPaths )
+: m_bHandleQuotedString( vbHandleQuotes )
+, m_bAcceptNumbers( vbAcceptNumbers )
+, m_bHandleDirPaths( vbHandleDirPaths )
+, m_bHandleAnything( false )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValString constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// vbHandleByCmd - (R) True = Command processes *this option, false = not handled.
+// vbHandleQuotes - (R) True = Parse a string surrounded by quotes spaces are not delimitors, false = only text up to next delimiting space character. (Dflt = false)
+// vbAcceptNumbers - (R) True = Parse a string and accept as a number if number, false = numbers not recognised as string types. (Dflt = false)
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValString::CMICmdArgValString( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd, const bool vbHandleQuotes /* = false */, const bool vbAcceptNumbers /* = false */ )
+: CMICmdArgValBaseTemplate( vrArgName, vbMandatory, vbHandleByCmd )
+, m_bHandleQuotedString( vbHandleQuotes )
+, m_bAcceptNumbers( vbAcceptNumbers )
+, m_bHandleDirPaths( false )
+, m_bHandleAnything( false )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValString destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValString::~CMICmdArgValString( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Parse the command's argument options string and try to extract the value *this
+// argument is looking for.
+// Type: Overridden.
+// Args: vrwArgContext - (RW) The command's argument options string.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValString::Validate( CMICmdArgContext & vrwArgContext )
+{
+ if( vrwArgContext.IsEmpty() )
+ return MIstatus::success;
+
+ if( m_bHandleQuotedString )
+ return (ValidateQuotedText( vrwArgContext ) || ValidateQuotedTextEmbedded( vrwArgContext ) );
+
+ return ValidateSingleText( vrwArgContext );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Parse the command's argument options string and try to extract only the next
+// word delimited by the next space.
+// Type: Method.
+// Args: vrwArgContext - (RW) The command's argument options string.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValString::ValidateSingleText( CMICmdArgContext & vrwArgContext )
+{
+ if( vrwArgContext.GetNumberArgsPresent() == 1 )
+ {
+ const CMIUtilString & rArg( vrwArgContext.GetArgsLeftToParse() );
+ if( IsStringArg( rArg ) )
+ {
+ m_bFound = true;
+ m_bValid = true;
+ m_argValue = rArg;
+ vrwArgContext.RemoveArg( rArg );
+ return MIstatus::success;
+ }
+ else
+ return MIstatus::failure;
+ }
+
+ // More than one option...
+ const CMIUtilString::VecString_t vecOptions( vrwArgContext.GetArgs() );
+ CMIUtilString::VecString_t::const_iterator it = vecOptions.begin();
+ while( it != vecOptions.end() )
+ {
+ const CMIUtilString & rArg( *it );
+ if( IsStringArg( rArg ) )
+ {
+ m_bFound = true;
+
+ if( vrwArgContext.RemoveArg( rArg ) )
+ {
+ m_bValid = true;
+ m_argValue = rArg;
+ return MIstatus::success;
+ }
+ else
+ return MIstatus::failure;
+ }
+
+ // Next
+ ++it;
+ }
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Parse the command's argument options string and try to extract all the words
+// between quotes then delimited by the next space. Can fall through to
+// ValidateSingleText() or ValidateQuotedQuotedTextEmbedded().
+// Type: Method.
+// Args: vrwArgContext - (RW) The command's argument options string.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValString::ValidateQuotedText( CMICmdArgContext & vrwArgContext )
+{
+ // CODETAG_QUOTEDTEXT_SIMILAR_CODE
+ CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse();
+ const MIchar cQuote = '"';
+
+ // Look for first quote of two
+ MIint nPos = strOptions.find( cQuote );
+ if( nPos == (MIint) std::string::npos )
+ return ValidateSingleText( vrwArgContext );
+
+ // Is one and only quote at end of the string
+ const MIint nLen = strOptions.length();
+ if( nPos == (MIint)(nLen - 1) )
+ return MIstatus::failure;
+
+ // Quote must be the first character in the string or be preceeded by a space
+ if( (nPos > 0) && (strOptions[ nPos - 1 ] != ' ') )
+ return MIstatus::failure;
+
+ // Need to find the other quote
+ const MIint nPos2 = strOptions.rfind( cQuote );
+ if( nPos2 == (MIint) std::string::npos )
+ return MIstatus::failure;
+
+ // Is there quotes surrounding string formatting embedded quotes
+ if( IsStringArgQuotedQuotedTextEmbedded( strOptions ) )
+ return ValidateQuotedQuotedTextEmbedded( vrwArgContext );
+
+ // Make sure not same back quote, need two quotes
+ if( nPos == nPos2 )
+ return MIstatus::failure;
+
+ // Extract quoted text
+ const CMIUtilString strQuotedTxt = strOptions.substr( nPos, nPos2 - nPos + 1 ).c_str();
+ if( vrwArgContext.RemoveArg( strQuotedTxt ) )
+ {
+ m_bFound = true;
+ m_bValid = true;
+ m_argValue = strOptions.substr( nPos + 1, nPos2 - nPos - 1 ).c_str();
+ return MIstatus::success;
+ }
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Parse the command's argument options string and try to extract all the words
+// between quotes then delimited by the next space. If there any string format
+// characters '\\' used to embed quotes these are ignored i.e. "\\\"%5d\\\""
+// becomes "%5d". Can fall through to ValidateQuotedText().
+// Type: Method.
+// Args: vrwArgContext - (RW) The command's argument options string.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValString::ValidateQuotedTextEmbedded( CMICmdArgContext & vrwArgContext )
+{
+ // CODETAG_QUOTEDTEXT_SIMILAR_CODE
+ CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse();
+ const MIchar cBckSlash = '\\';
+ const MIint nPos = strOptions.find( cBckSlash );
+ if( nPos == (MIint) std::string::npos )
+ return ValidateQuotedText( vrwArgContext );
+
+ // Back slash must be the first character in the string or be preceeded by a space
+ // or '\\'
+ const MIchar cSpace = ' ';
+ if( (nPos > 0) && (strOptions[ nPos - 1 ] != cSpace) )
+ return MIstatus::failure;
+
+ // Need to find the other back slash
+ const MIint nPos2 = strOptions.rfind( cBckSlash );
+ if( nPos2 == (MIint) std::string::npos )
+ return MIstatus::failure;
+
+ // Make sure not same back slash, need two slashs
+ if( nPos == nPos2 )
+ return MIstatus::failure;
+
+ // Look for the two quotes
+ const MIint nLen = strOptions.length();
+ const MIchar cQuote = '"';
+ const MIint nPosQuote1 = nPos + 1;
+ const MIint nPosQuote2 = (nPos2 < nLen) ? nPos2 + 1 : nPos2;
+ if( (nPosQuote1 != nPosQuote2) &&
+ (strOptions[ nPosQuote1 ] != cQuote) && (strOptions[ nPosQuote2 ] != cQuote) )
+ return MIstatus::failure;
+
+ // Extract quoted text
+ const CMIUtilString strQuotedTxt = strOptions.substr( nPos, nPosQuote2 - nPos + 1 ).c_str();
+ if( vrwArgContext.RemoveArg( strQuotedTxt ) )
+ {
+ m_bFound = true;
+ m_bValid = true;
+ m_argValue = strQuotedTxt;
+ return MIstatus::success;
+ }
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Parse the command's argument options string and try to extract all the words
+// between quotes then delimited by the next space. If there any string format
+// characters '\\' used to embed quotes these are ignored i.e. "\\\"%5d\\\""
+// becomes "%5d".
+// Type: Method.
+// Args: vrwArgContext - (RW) The command's argument options string.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValString::ValidateQuotedQuotedTextEmbedded( CMICmdArgContext & vrwArgContext )
+{
+ // CODETAG_QUOTEDTEXT_SIMILAR_CODE
+ CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse();
+ const MIint nPos = strOptions.find( "\"\\\"" );
+ if( nPos == (MIint) std::string::npos )
+ return MIstatus::failure;
+
+ const MIint nPos2 = strOptions.rfind( "\\\"\"" );
+ if( nPos2 == (MIint) std::string::npos )
+ return MIstatus::failure;
+
+ const MIint nLen = strOptions.length();
+ if( (nLen > 5) && ((nPos + 2) == (nPos2 - 2)) )
+ return MIstatus::failure;
+
+ // Quote must be the first character in the string or be preceeded by a space
+ // or '\\'
+ const MIchar cSpace = ' ';
+ if( (nPos > 0) && (strOptions[ nPos - 1 ] != cSpace) )
+ return MIstatus::failure;
+
+ // Extract quoted text
+ const CMIUtilString strQuotedTxt = strOptions.substr( nPos, nPos2 - nPos + 3 ).c_str();
+ if( vrwArgContext.RemoveArg( strQuotedTxt ) )
+ {
+ m_bFound = true;
+ m_bValid = true;
+ m_argValue = strQuotedTxt;
+ return MIstatus::success;
+ }
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the string and determine if it is a valid string type argument.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes valid arg, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValString::IsStringArg( const CMIUtilString & vrTxt ) const
+{
+ if( m_bHandleQuotedString )
+ return (IsStringArgQuotedText( vrTxt ) ||
+ IsStringArgQuotedTextEmbedded( vrTxt ) ||
+ IsStringArgQuotedQuotedTextEmbedded( vrTxt ) ||
+ IsStringArgSingleText( vrTxt ) ); // Still test for this as could just be one word still
+
+ return IsStringArgSingleText( vrTxt );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the string and determine if it is a valid string type argument or
+// option value. If the string looks like a long option, short option, a thread
+// group ID or just a number it is rejected as a string type value. There is an
+// option to allow the string to accept a number as a string type.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes valid argument value, false = something else.
+// Throws: None.
+//--
+bool CMICmdArgValString::IsStringArgSingleText( const CMIUtilString & vrTxt ) const
+{
+ // Accept anything as string word
+ if( m_bHandleAnything )
+ return true;
+
+ if( !m_bHandleDirPaths )
+ {
+ // Look for directory file paths, if found reject
+ const bool bHavePosSlash = (vrTxt.find_first_of( "/" ) != std::string::npos);
+ const bool bHaveBckSlash = (vrTxt.find_first_of( "\\" ) != std::string::npos);
+ if( bHavePosSlash || bHaveBckSlash )
+ return false;
+ }
+
+ // Look for --someLongOption, if found reject
+ if( 0 == vrTxt.find( "--" ) )
+ return false;
+
+ // Look for -f type short options, if found reject
+ if( (0 == vrTxt.find( "-" )) && (vrTxt.length() == 2) )
+ return false;
+
+ // Look for thread group i1 i2 i3...., if found reject
+ if( (vrTxt.find( "i" ) == 0) && ::isdigit( vrTxt[ 1 ]) )
+ return false;
+
+ // Look for numbers, if found reject
+ if( !m_bAcceptNumbers && vrTxt.IsNumber() )
+ return false;
+
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the string and determine if it is a valid string type argument.
+// Take into account quotes surrounding the text. Note this function falls
+// through to IsStringArgSingleText() should the criteria match fail.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes valid arg, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValString::IsStringArgQuotedText( const CMIUtilString & vrTxt ) const
+{
+ // CODETAG_QUOTEDTEXT_SIMILAR_CODE
+ const MIchar cQuote = '"';
+ const MIint nPos = vrTxt.find( cQuote );
+ if( nPos == (MIint) std::string::npos )
+ return false;
+
+ // Is one and only quote at end of the string
+ if( nPos == (MIint)(vrTxt.length() - 1) )
+ return false;
+
+ // Quote must be the first character in the string or be preceeded by a space
+ // Also check for embedded string formating quote
+ const MIchar cBckSlash = '\\';
+ const MIchar cSpace = ' ';
+ if( (nPos > 1) && (vrTxt[ nPos - 1 ] == cBckSlash) && (vrTxt[ nPos - 2 ] != cSpace) )
+ {
+ return false;
+ }
+ if( (nPos > 0) && (vrTxt[ nPos - 1 ] != cSpace) )
+ return false;
+
+ // Need to find the other quote
+ const MIint nPos2 = vrTxt.rfind( cQuote );
+ if( nPos2 == (MIint) std::string::npos )
+ return false;
+
+ // Make sure not same quote, need two quotes
+ if( nPos == nPos2 )
+ return MIstatus::failure;
+
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the string and determine if it is a valid string type argument.
+// Take into account quotes surrounding the text. Take into account string format
+// embedded quotes surrounding the text i.e. "\\\"%5d\\\"". Note this function falls
+// through to IsStringArgQuotedText() should the criteria match fail.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes valid arg, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValString::IsStringArgQuotedTextEmbedded( const CMIUtilString & vrTxt ) const
+{
+ // CODETAG_QUOTEDTEXT_SIMILAR_CODE
+ const MIchar cBckSlash = '\\';
+ const MIint nPos = vrTxt.find( cBckSlash );
+ if( nPos == (MIint) std::string::npos )
+ return false;
+
+ // Slash must be the first character in the string or be preceeded by a space
+ const MIchar cSpace = ' ';
+ if( (nPos > 0) && (vrTxt[ nPos - 1 ] != cSpace) )
+ return false;
+
+ // Need to find the other matching slash
+ const MIint nPos2 = vrTxt.rfind( cBckSlash );
+ if( nPos2 == (MIint) std::string::npos )
+ return false;
+
+ // Make sure not same back slash, need two slashs
+ if( nPos == nPos2 )
+ return MIstatus::failure;
+
+ return false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the string and determine if it is a valid string type argument.
+// Take into account quotes surrounding the text. Take into account string format
+// embedded quotes surrounding the text i.e. "\\\"%5d\\\"". Note this function falls
+// through to IsStringArgQuotedTextEmbedded() should the criteria match fail.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes valid arg, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValString::IsStringArgQuotedQuotedTextEmbedded( const CMIUtilString & vrTxt ) const
+{
+ const MIint nPos = vrTxt.find( "\"\\\"" );
+ if( nPos == (MIint) std::string::npos )
+ return false;
+
+ const MIint nPos2 = vrTxt.rfind( "\\\"\"" );
+ if( nPos2 == (MIint) std::string::npos )
+ return false;
+
+ const MIint nLen = vrTxt.length();
+ if( (nLen > 5) && ((nPos + 2) == (nPos2 - 2)) )
+ return false;
+
+ return true;
+}
diff --git a/tools/lldb-mi/MICmdArgValString.h b/tools/lldb-mi/MICmdArgValString.h
new file mode 100644
index 000000000000..ab411a02dc88
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValString.h
@@ -0,0 +1,76 @@
+//===-- MICmdArgValString.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValString.h
+//
+// Overview: CMICmdArgValString interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdArgValBase.h"
+
+// Declarations:
+class CMICmdArgContext;
+
+//++ ============================================================================
+// Details: MI common code class. Command argument class. Arguments object
+// needing specialization derived from the CMICmdArgValBase class.
+// An argument knows what type of argument it is and how it is to
+// interpret the options (context) string to find and validate a matching
+// argument and so extract a value from it .
+// Based on the Interpreter pattern.
+// Gotchas: None.
+// Authors: Illya Rudkin 15/04/2014.
+// Changes: None.
+//--
+class CMICmdArgValString : public CMICmdArgValBaseTemplate< CMIUtilString >
+{
+// Methods:
+public:
+ /* ctor */ CMICmdArgValString( void );
+ /* ctor */ CMICmdArgValString( const bool vbAnything );
+ /* ctor */ CMICmdArgValString( const bool vbHandleQuotes, const bool vbAcceptNumbers, const bool vbHandleDirPaths );
+ /* ctor */ CMICmdArgValString( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd, const bool vbHandleQuotes = false, const bool vbAcceptNumbers = false );
+ //
+ bool IsStringArg( const CMIUtilString & vrTxt ) const;
+
+// Overridden:
+public:
+ // From CMICmdArgValBase
+ /* dtor */ virtual ~CMICmdArgValString( void );
+ // From CMICmdArgSet::IArg
+ virtual bool Validate( CMICmdArgContext & vrwArgContext );
+
+// Methods:
+private:
+ bool ValidateSingleText( CMICmdArgContext & vrwArgContext );
+ bool ValidateQuotedText( CMICmdArgContext & vrwArgContext );
+ bool ValidateQuotedTextEmbedded( CMICmdArgContext & vrwArgContext );
+ bool ValidateQuotedQuotedTextEmbedded( CMICmdArgContext & vrwArgContext );
+ bool IsStringArgSingleText( const CMIUtilString & vrTxt ) const;
+ bool IsStringArgQuotedText( const CMIUtilString & vrTxt ) const;
+ bool IsStringArgQuotedTextEmbedded( const CMIUtilString & vrTxt ) const;
+ bool IsStringArgQuotedQuotedTextEmbedded( const CMIUtilString & vrTxt ) const;
+
+// Attribute:
+private:
+ bool m_bHandleQuotedString; // True = Parse a string surrounded by quotes spaces are not delimitors, false = only text up to next delimiting space character
+ bool m_bAcceptNumbers; // True = Parse a string and accept as a number if number, false = numbers not recognised as string types
+ bool m_bHandleDirPaths; // True = Parse a string and accept directory file style string if present, false = directory file path not accepted
+ bool m_bHandleAnything; // True = Parse a string and accept anything if present, false = validate for criteria matches
+};
diff --git a/tools/lldb-mi/MICmdArgValThreadGrp.cpp b/tools/lldb-mi/MICmdArgValThreadGrp.cpp
new file mode 100644
index 000000000000..7d3290482119
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValThreadGrp.cpp
@@ -0,0 +1,173 @@
+//===-- MICmdArgValThreadGrp.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValThreadGrp.cpp
+//
+// Overview: CMICmdArgValThreadGrp implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdArgValThreadGrp.h"
+#include "MICmdArgContext.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValThreadGrp constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValThreadGrp::CMICmdArgValThreadGrp( void )
+: m_nThreadGrp( 0 )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValThreadGrp constructor.
+// Type: Method.
+// Args: vrArgName - (R) Argument's name to search by.
+// vbMandatory - (R) True = Yes must be present, false = optional argument.
+// vbHandleByCmd - (R) True = Command processes *this option, false = not handled.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValThreadGrp::CMICmdArgValThreadGrp( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd )
+: CMICmdArgValBaseTemplate( vrArgName, vbMandatory, vbHandleByCmd )
+, m_nThreadGrp( 0 )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdArgValThreadGrp destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdArgValThreadGrp::~CMICmdArgValThreadGrp( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Parse the command's argument options string and try to extract the value *this
+// argument is looking for.
+// Type: Overridden.
+// Args: vwArgContext - (RW) The command's argument options string.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValThreadGrp::Validate( CMICmdArgContext & vwArgContext )
+{
+ if( vwArgContext.IsEmpty() )
+ return MIstatus::success;
+
+ if( vwArgContext.GetNumberArgsPresent() == 1 )
+ {
+ const CMIUtilString & rArg( vwArgContext.GetArgsLeftToParse() );
+ if( IsArgThreadGrp( rArg ) && ExtractNumber( rArg ) )
+ {
+ m_bFound = true;
+ m_bValid = true;
+ m_argValue = GetNumber();
+ vwArgContext.RemoveArg( rArg );
+ return MIstatus::success;
+ }
+ else
+ return MIstatus::failure;
+ }
+
+ // More than one option...
+ const CMIUtilString::VecString_t vecOptions( vwArgContext.GetArgs() );
+ CMIUtilString::VecString_t::const_iterator it = vecOptions.begin();
+ while( it != vecOptions.end() )
+ {
+ const CMIUtilString & rArg( *it );
+ if( IsArgThreadGrp( rArg ) && ExtractNumber( rArg ) )
+ {
+ m_bFound = true;
+
+ if( vwArgContext.RemoveArg( rArg ) )
+ {
+ m_bValid = true;
+ m_argValue = GetNumber();
+ return MIstatus::success;
+ }
+ else
+ return MIstatus::failure;
+ }
+
+ // Next
+ ++it;
+ }
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the string and determine if it is a valid string type argument.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: bool - True = yes valid arg, false = no.
+// Throws: None.
+//--
+bool CMICmdArgValThreadGrp::IsArgThreadGrp( const CMIUtilString & vrTxt ) const
+{
+ // Look for i1 i2 i3....
+ const MIint nPos = vrTxt.find_first_of( "i" );
+ if( nPos != 0 )
+ return false;
+
+ const CMIUtilString strNum = vrTxt.substr( 1 ).c_str();
+ if( !strNum.IsNumber() )
+ return false;
+
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Extract the thread group number from the thread group argument.
+// Type: Method.
+// Args: vrTxt - (R) Some text.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdArgValThreadGrp::ExtractNumber( const CMIUtilString & vrTxt )
+{
+ const CMIUtilString strNum = vrTxt.substr( 1 ).c_str();
+ MIint64 nNumber = 0;
+ bool bOk = strNum.ExtractNumber( nNumber );
+ if( bOk )
+ {
+ m_nThreadGrp = static_cast< MIuint >( nNumber );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the thread group ID found in the argument.
+// Type: Method.
+// Args: None.
+// Return: MIuint - Thread group ID.
+// Throws: None.
+//--
+MIuint CMICmdArgValThreadGrp::GetNumber( void ) const
+{
+ return m_nThreadGrp;
+}
+
diff --git a/tools/lldb-mi/MICmdArgValThreadGrp.h b/tools/lldb-mi/MICmdArgValThreadGrp.h
new file mode 100644
index 000000000000..8903597dbca1
--- /dev/null
+++ b/tools/lldb-mi/MICmdArgValThreadGrp.h
@@ -0,0 +1,66 @@
+//===-- MICmdArgValThreadGrp.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdArgValThreadGrp.h
+//
+// Overview: CMICmdArgValThreadGrp interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdArgValBase.h"
+
+// Declarations:
+class CMICmdArgContext;
+
+//++ ============================================================================
+// Details: MI common code class. Command argument class. Arguments object
+// needing specialization derived from the CMICmdArgValBase class.
+// An argument knows what type of argument it is and how it is to
+// interpret the options (context) string to find and validate a matching
+// argument and so extract a value from it. Thread group looks like
+// "i1" in the options text.
+// Based on the Interpreter pattern.
+// Gotchas: None.
+// Authors: Illya Rudkin 15/04/2014.
+// Changes: None.
+//--
+class CMICmdArgValThreadGrp : public CMICmdArgValBaseTemplate< MIuint >
+{
+// Methods:
+public:
+ /* ctor */ CMICmdArgValThreadGrp( void );
+ /* ctor */ CMICmdArgValThreadGrp( const CMIUtilString & vrArgName, const bool vbMandatory, const bool vbHandleByCmd );
+ //
+ bool IsArgThreadGrp( const CMIUtilString & vrTxt ) const;
+
+// Overridden:
+public:
+ // From CMICmdArgValBase
+ /* dtor */ virtual ~CMICmdArgValThreadGrp( void );
+ // From CMICmdArgSet::IArg
+ virtual bool Validate( CMICmdArgContext & vArgContext );
+
+// Methods:
+private:
+ bool ExtractNumber( const CMIUtilString & vrTxt );
+ MIuint GetNumber( void ) const;
+
+// Attributes:
+private:
+ MIuint m_nThreadGrp;
+};
diff --git a/tools/lldb-mi/MICmdBase.cpp b/tools/lldb-mi/MICmdBase.cpp
new file mode 100644
index 000000000000..cedcba7e042f
--- /dev/null
+++ b/tools/lldb-mi/MICmdBase.cpp
@@ -0,0 +1,263 @@
+//===-- MICmdBase.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdBase.cpp
+//
+// Overview: CMICmdBase implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdBase.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdBase constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdBase::CMICmdBase( void )
+: m_pSelfCreatorFn( nullptr )
+, m_rLLDBDebugSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() )
+, m_bHasResultRecordExtra( false )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdBase destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdBase::~CMICmdBase( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function.
+// Type: Overridden.
+// Args: None.
+// Return: SMICmdData & - *this command's present status/data/information.
+// Throws: None.
+//--
+const SMICmdData & CMICmdBase::GetCmdData( void ) const
+{
+ return m_cmdData;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString & - *this command's current error description.
+// Empty string indicates command status ok.
+// Throws: None.
+//--
+const CMIUtilString & CMICmdBase::GetErrorDescription( void ) const
+{
+ return m_strCurrentErrDescription;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The CMICmdFactory requires this function. Retrieve the command and argument
+// options description string.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString & - Command decription.
+// Throws: None.
+//--
+const CMIUtilString & CMICmdBase::GetMiCmd( void ) const
+{
+ return m_strMiCmd;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. A command must be given working data and
+// provide data about its status or provide information to other objects.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdBase::SetCmdData( const SMICmdData & vCmdData )
+{
+ m_cmdData = vCmdData;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The command factory requires this function. The factory calls this function
+// so it can obtain *this command's creation function.
+// Type: Overridden.
+// Args: None.
+// Return: CMICmdFactory::CmdCreatorFnPtr - Function pointer.
+// Throws: None.
+//--
+CMICmdFactory::CmdCreatorFnPtr CMICmdBase::GetCmdCreatorFn( void ) const
+{
+ return m_pSelfCreatorFn;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: If a command is an event type (has callbacks registered with SBListener) it
+// needs to inform the Invoker that it has finished its work so that the
+// Invoker can tidy up and call the commands Acknowledge function (yes the
+// command itself could call the Acknowledge itself but not doing that way).
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMICmdBase::CmdFinishedTellInvoker( void ) const
+{
+ CMICmdInvoker::Instance().CmdExecuteFinished( const_cast< CMICmdBase & >( *this ) );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Returns the final version of the MI result record built up in the command's
+// Acknowledge function. The one line text of MI result.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString & - MI text version of the MI result record.
+// Throws: None.
+//--
+const CMIUtilString & CMICmdBase::GetMIResultRecord( void ) const
+{
+ return m_miResultRecord.GetString();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve from the command additional MI result to its 1 line response.
+// Because of using LLDB addtional 'fake'/hack output is sometimes required to
+// help the driver client operate i.e. Eclipse.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString & - MI text version of the MI result record.
+// Throws: None.
+//--
+const CMIUtilString & CMICmdBase::GetMIResultRecordExtra( void ) const
+{
+ return m_miResultRecordExtra;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Hss *this command got additional MI result to its 1 line response.
+// Because of using LLDB addtional 'fake'/hack output is sometimes required to
+// help the driver client operate i.e. Eclipse.
+// Type: Overridden.
+// Args: None.
+// Return: bool - True = Yes have additional MI output, false = no nothing extra.
+// Throws: None.
+//--
+bool CMICmdBase::HasMIResultRecordExtra( void ) const
+{
+ return m_bHasResultRecordExtra;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Short cut function to enter error information into the command's metadata
+// object and set the command's error status.
+// Type: Method.
+// Args: rErrMsg - (R) Error description.
+// Return: None.
+// Throws: None.
+//--
+void CMICmdBase::SetError( const CMIUtilString & rErrMsg )
+{
+ m_cmdData.bCmdValid = false;
+ m_cmdData.strErrorDescription = rErrMsg;
+ m_cmdData.bCmdExecutedSuccessfully = false;
+
+ const CMICmnMIValueResult valueResult( "msg", CMICmnMIValueConst( rErrMsg ) );
+ const CMICmnMIResultRecord miResultRecord( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, valueResult );
+ m_miResultRecord = miResultRecord;
+ m_cmdData.strMiCmdResultRecord = miResultRecord.GetString();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Ask a command to provide its unique identifier.
+// Type: Method.
+// Args: A unique identifier for this command class.
+// Return: None.
+// Throws: None.
+//--
+MIuint CMICmdBase::GetGUID( void )
+{
+ MIuint64 vptr = reinterpret_cast< MIuint64 >( this );
+ MIuint id = (vptr ) & 0xFFFFFFFF;
+ id ^= (vptr >> 32) & 0xFFFFFFFF;
+
+ return id;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdBase::ParseArgs( void )
+{
+ // Do nothing - override to implement
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Having previously given CMICmdArgSet m_setCmdArgs all the argument or option
+// definitions for the command to handle proceed to parse and validate the
+// command's options text for those arguments and extract the values for each if
+// any.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdBase::ParseValidateCmdOptions( void )
+{
+ CMICmdArgContext argCntxt( m_cmdData.strMiCmdOption );
+ if( m_setCmdArgs.Validate( m_cmdData.strMiCmd, argCntxt ) )
+ return MIstatus::success;
+
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_ARGS ), m_cmdData.strMiCmd.c_str(), m_setCmdArgs.GetErrorDescription().c_str() ) );
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: If the MI Driver is not operating via a client i.e. Eclipse but say operating
+// on a executable passed in as a argument to the drive then what should the driver
+// do on a command failing? Either continue operating or exit the application.
+// Override this function where a command failure cannot allow the driver to
+// continue operating.
+// Type: Overrideable.
+// Args: None.
+// Return: bool - True = Fatal if command fails, false = can continue if command fails.
+// Throws: None.
+//--
+bool CMICmdBase::GetExitAppOnCommandFailure( void ) const
+{
+ return false;
+}
diff --git a/tools/lldb-mi/MICmdBase.h b/tools/lldb-mi/MICmdBase.h
new file mode 100644
index 000000000000..b05e97d2082d
--- /dev/null
+++ b/tools/lldb-mi/MICmdBase.h
@@ -0,0 +1,156 @@
+//===-- MICmdBase.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdBase.h
+//
+// Overview: CMICmdBase interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MIUtilString.h"
+#include "MICmnBase.h"
+#include "MICmnResources.h"
+#include "MICmdInvoker.h"
+#include "MICmdFactory.h"
+#include "MICmdData.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmdArgSet.h"
+
+// Declarations:
+class CMICmnLLDBDebugSessionInfo;
+
+//++ ============================================================================
+// Details: MI command base class. MI commands derive from this base class.
+// The Command Factory creates command objects and passes them to the
+// Command Invoker. The Invoker takes ownersip of any commands created
+// which means it is the only object to delete them when a command is
+// finished working. Commands do not delete themselves.
+// There are two types of command implicitly defined by the state of
+// the m_bWaitForEventFromSBDebugger flag. There is the event type
+// command which registers (command fn) callbacks with the SBListener
+// does some work then wakes up again when called back, does more work
+// perhaps, ends, then the Invoker calls the command's Acknowledge
+// function. The other type of command is one that just does some work,
+// ends, then the Invoker calls the command's Acknowledge function. No
+// events set up.
+// A command's Execute(), Acknowledge() and event callback functions are
+// carried out in the main thread.
+// A command may use the argument derived object classes (CMICmdArgValBase)
+// to factor handling and parsing of different types of arguments
+// presented to a command. A command will produce an error should it
+// be presented with arguments or options it does not understand.
+// Gotchas: None.
+// Authors: Illya Rudkin 18/02/2014.
+// Changes: None.
+//--
+class CMICmdBase
+: public CMICmnBase
+, public CMICmdInvoker::ICmd
+, public CMICmdFactory::ICmd
+{
+// Methods:
+public:
+ /* ctor */ CMICmdBase( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual const SMICmdData & GetCmdData( void ) const;
+ virtual const CMIUtilString & GetErrorDescription( void ) const;
+ virtual bool SetCmdData( const SMICmdData & vCmdData );
+ virtual void CmdFinishedTellInvoker( void ) const;
+ virtual const CMIUtilString & GetMIResultRecord( void ) const;
+ virtual const CMIUtilString & GetMIResultRecordExtra( void ) const;
+ virtual bool HasMIResultRecordExtra( void ) const;
+ virtual bool ParseArgs( void );
+ // From CMICmdFactory::ICmd
+ virtual const CMIUtilString & GetMiCmd( void ) const;
+ virtual CMICmdFactory::CmdCreatorFnPtr GetCmdCreatorFn( void ) const;
+
+ virtual MIuint GetGUID( void );
+
+// Overrideable:
+public:
+ /* dtor */ virtual ~CMICmdBase( void );
+ virtual bool GetExitAppOnCommandFailure( void ) const;
+
+// Methods:
+protected:
+ void SetError( const CMIUtilString & rErrMsg );
+ template< class T >
+ T * GetOption( const CMIUtilString & vStrOptionName );
+ bool ParseValidateCmdOptions( void );
+
+// Attributes:
+protected:
+ CMICmdFactory::CmdCreatorFnPtr m_pSelfCreatorFn;
+ CMIUtilString m_strCurrentErrDescription; // Reason for Execute or Acknowledge function failure
+ SMICmdData m_cmdData; // Holds information/status of *this command. Used by other MI code to report or determine state of a command.
+ bool m_bWaitForEventFromSBDebugger; // True = yes event type command wait, false = command calls Acknowledge() straight after Execute() no waiting
+ CMIUtilString m_strMiCmd; // The MI text identifying *this command i.e. 'break-insert'
+ CMICmnMIResultRecord m_miResultRecord; // This is completed in the Acknowledge() function and returned to the Command Invoker to proceed stdout output. Each command forms 1 response to its input.
+ CMIUtilString m_miResultRecordExtra; // This is completed in the Acknowledge() function and returned to the Command Invoker to proceed stdout output. Hack command produce more response text to help the client because of using LLDB
+ CMICmnLLDBDebugSessionInfo & m_rLLDBDebugSessionInfo; // Access to command sharing information or data across any and all command based derived classes.
+ bool m_bHasResultRecordExtra; // True = Yes command produced additional MI output to its 1 line response, false = no extra MI output formed.
+ CMICmdArgSet m_setCmdArgs; // The list of arguments *this command needs to parse from the options string to carry out work.
+};
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the command argument or option object pointer so that it can be
+// examined. If the option found and valid get the value (number, string or list
+// - see CMICmdArgValBase class) from it to use with the command's decision
+// making. If the argument is not found the command's error description is set
+// describing the error condition.
+// Type: Template method.
+// Args: vStrOptionName - (R) The text name of the argument or option to search for in
+// the list of the command's possible arguments or options.
+// Return: T * - CMICmdArgValBase derived object.
+// - NULL = function has failed, unable to retrieve the option/arg object.
+// Throws: None.
+//--
+template< class T >
+T * CMICmdBase::GetOption( const CMIUtilString & vStrOptionName )
+{
+ CMICmdArgValBase * pPtrBase = nullptr;
+ if( !m_setCmdArgs.GetArg( vStrOptionName, pPtrBase ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), vStrOptionName.c_str() ) );
+ return nullptr;
+ }
+
+ return static_cast< T * >( pPtrBase );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the command argument or option object pointer using template function
+// CMICmdBase::GetOption(). Should the argument (by name) not be found the
+// command will exit with a failure (set in GetOption()).
+// Type: Preprocessor macro.
+// Args: a - (R) The actual variable's name.
+// b - (R) The type of variable (appended to CMICmdArgVal i.e. CMICmdArgValString).
+// c - (R) The text name of the argument or option to search for in the list of
+// the command's possible arguments or options.
+// Return: T * - CMICmdArgValBase derived object.
+// - NULL = function has failed, unable to retrieve the option/arg object.
+// Throws: None.
+//--
+#define CMICMDBASE_GETOPTION( a, b, c ) \
+ CMICmdArgVal##b * a = CMICmdBase::GetOption< CMICmdArgVal##b >( c );\
+ if( a == nullptr ) \
+ return MIstatus::failure;
+// This comment is to stop compile warning for #define
diff --git a/tools/lldb-mi/MICmdCmd.cpp b/tools/lldb-mi/MICmdCmd.cpp
new file mode 100644
index 000000000000..3c6d52b24769
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmd.cpp
@@ -0,0 +1,174 @@
+//===-- MICmdCmd.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmd.cpp
+//
+// Overview: CMICmdCmdEnablePrettyPrinting implementation.
+// CMICmdCmdSource implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdCmd.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdEnablePrettyPrinting constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdEnablePrettyPrinting::CMICmdCmdEnablePrettyPrinting( void )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "enable-pretty-printing";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdEnablePrettyPrinting::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdEnablePrettyPrinting destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdEnablePrettyPrinting::~CMICmdCmdEnablePrettyPrinting( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdEnablePrettyPrinting::Execute( void )
+{
+ // Do nothing
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdEnablePrettyPrinting::Acknowledge( void )
+{
+ const CMICmnMIValueConst miValueConst( "0" );
+ const CMICmnMIValueResult miValueResult( "supported", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdEnablePrettyPrinting::CreateSelf( void )
+{
+ return new CMICmdCmdEnablePrettyPrinting();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdSource constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdSource::CMICmdCmdSource( void )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "source";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdSource::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdSource destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdSource::~CMICmdCmdSource( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdSource::Execute( void )
+{
+ // Do nothing
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdSource::Acknowledge( void )
+{
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdSource::CreateSelf( void )
+{
+ return new CMICmdCmdSource();
+}
diff --git a/tools/lldb-mi/MICmdCmd.h b/tools/lldb-mi/MICmdCmd.h
new file mode 100644
index 000000000000..c2ab6896e689
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmd.h
@@ -0,0 +1,104 @@
+//===-- MICmdCmd.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmd.h
+//
+// Overview: CMICmdCmdEnablePrettyPrinting interface.
+// CMICmdCmdSource interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+/*
+MI commands implemented are:
+ See MICmdCommands.cpp
+*/
+
+#pragma once
+
+// Third party headers:
+#include <vector>
+#include <lldb/API/SBBreakpoint.h>
+#include <lldb/API/SBCommandReturnObject.h>
+
+// In-house headers:
+#include "MICmdBase.h"
+#include "MICmnMIValueTuple.h"
+#include "MICmnMIValueList.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "enable-pretty-printing".
+// Enables Python base pretty printing.
+// Ref: http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Variable-Objects.html
+// Gotchas: None.
+// Authors: Illya Rudkin 03/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdEnablePrettyPrinting : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdEnablePrettyPrinting( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdEnablePrettyPrinting( void );
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "source".
+// Gotchas: None.
+// Authors: Illya Rudkin 05/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdSource
+ : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdSource( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdSource( void );
+};
diff --git a/tools/lldb-mi/MICmdCmdBreak.cpp b/tools/lldb-mi/MICmdCmdBreak.cpp
new file mode 100644
index 000000000000..f0e9acfe9082
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdBreak.cpp
@@ -0,0 +1,1026 @@
+//===-- MICmdCmdBreak.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdBreak.cpp
+//
+// Overview: CMICmdCmdBreakInsert implementation.
+// CMICmdCmdBreakDelete implementation.
+// CMICmdCmdBreakDisable implementation.
+// CMICmdCmdBreakEnable implementation.
+// CMICmdCmdBreakAfter implementation.
+// CMICmdCmdBreakCondition implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third Party Headers:
+#include <lldb/API/SBBreakpointLocation.h>
+
+// In-house headers:
+#include "MICmdCmdBreak.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnMIOutOfBandRecord.h"
+#include "MICmnLLDBDebugger.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MICmdArgValFile.h"
+#include "MICmdArgValNumber.h"
+#include "MICmdArgValString.h"
+#include "MICmdArgValThreadGrp.h"
+#include "MICmdArgValOptionLong.h"
+#include "MICmdArgValOptionShort.h"
+#include "MICmdArgValListOfN.h"
+#include "MICmnStreamStdout.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdBreakInsert constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdBreakInsert::CMICmdCmdBreakInsert( void )
+: m_bBrkPtIsTemp( false )
+, m_bBrkPtIsPending( false )
+, m_nBrkPtIgnoreCount( 0 )
+, m_bBrkPtEnabled( false )
+, m_bBrkPtCondition( false )
+, m_bBrkPtThreadId( false )
+, m_nBrkPtThreadId( 0 )
+, m_constStrArgNamedTempBrkPt( "t" )
+, m_constStrArgNamedHWBrkPt( "h" )
+, m_constStrArgNamedPendinfBrkPt( "f" )
+, m_constStrArgNamedDisableBrkPt( "d" )
+, m_constStrArgNamedTracePt( "a" )
+, m_constStrArgNamedConditionalBrkPt( "c" )
+, m_constStrArgNamedInoreCnt( "i" )
+, m_constStrArgNamedRestrictBrkPtToThreadId( "p" )
+, m_constStrArgNamedLocation( "location" )
+, m_constStrArgNamedThreadGroup( "thread-group" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "break-insert";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdBreakInsert::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdBreakInsert destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdBreakInsert::~CMICmdCmdBreakInsert( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakInsert::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgNamedTempBrkPt, false, true )) );
+ //Not implemented bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgNamedHWBrkPt, false, false ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgNamedPendinfBrkPt, false, true, CMICmdArgValListBase::eArgValType_StringQuotedNumberPath, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgNamedDisableBrkPt, false, false ) ) );
+ //Not implemented bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgNamedTracePt, false, false ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgNamedConditionalBrkPt, false, true, CMICmdArgValListBase::eArgValType_StringQuoted, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgNamedInoreCnt, false, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgNamedRestrictBrkPtToThreadId, false, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgNamedLocation, false, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgNamedThreadGroup, false, true, CMICmdArgValListBase::eArgValType_ThreadGrp, 1 ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakInsert::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgTempBrkPt, OptionShort, m_constStrArgNamedTempBrkPt );
+ CMICMDBASE_GETOPTION( pArgThreadGroup, OptionLong, m_constStrArgNamedThreadGroup );
+ CMICMDBASE_GETOPTION( pArgLocation, String, m_constStrArgNamedLocation );
+ CMICMDBASE_GETOPTION( pArgIgnoreCnt, OptionShort, m_constStrArgNamedInoreCnt );
+ CMICMDBASE_GETOPTION( pArgPendingBrkPt, OptionShort, m_constStrArgNamedPendinfBrkPt );
+ CMICMDBASE_GETOPTION( pArgDisableBrkPt, OptionShort, m_constStrArgNamedDisableBrkPt );
+ CMICMDBASE_GETOPTION( pArgConditionalBrkPt, OptionShort, m_constStrArgNamedConditionalBrkPt );
+ CMICMDBASE_GETOPTION( pArgRestrictBrkPtToThreadId, OptionShort, m_constStrArgNamedRestrictBrkPtToThreadId );
+
+ m_bBrkPtEnabled = !pArgDisableBrkPt->GetFound();
+ m_bBrkPtIsTemp = pArgTempBrkPt->GetFound();
+ m_bHaveArgOptionThreadGrp = pArgThreadGroup->GetFound();
+ if( m_bHaveArgOptionThreadGrp )
+ {
+ MIuint nThreadGrp = 0;
+ pArgThreadGroup->GetExpectedOption< CMICmdArgValThreadGrp, MIuint >( nThreadGrp );
+ m_strArgOptionThreadGrp = CMIUtilString::Format( "i%d", nThreadGrp );
+ }
+ m_bBrkPtIsPending = pArgPendingBrkPt->GetFound();
+ if( pArgLocation->GetFound() )
+ m_brkName = pArgLocation->GetValue();
+ else if( m_bBrkPtIsPending )
+ {
+ pArgPendingBrkPt->GetExpectedOption< CMICmdArgValString, CMIUtilString >( m_brkName );
+ }
+ if( pArgIgnoreCnt->GetFound() )
+ {
+ pArgIgnoreCnt->GetExpectedOption< CMICmdArgValNumber, MIuint >( m_nBrkPtIgnoreCount );
+ }
+ m_bBrkPtCondition = pArgConditionalBrkPt->GetFound();
+ if( m_bBrkPtCondition )
+ {
+ pArgConditionalBrkPt->GetExpectedOption< CMICmdArgValString, CMIUtilString >( m_brkPtCondition );
+ }
+ m_bBrkPtThreadId = pArgRestrictBrkPtToThreadId->GetFound();
+ if( m_bBrkPtCondition )
+ {
+ pArgRestrictBrkPtToThreadId->GetExpectedOption< CMICmdArgValNumber, MIuint >( m_nBrkPtThreadId );
+ }
+
+ // Determine if break on a file line or at a function
+ BreakPoint_e eBrkPtType = eBreakPoint_NotDefineYet;
+ const CMIUtilString cColon = ":";
+ CMIUtilString fileName;
+ MIuint nFileLine = 0;
+ CMIUtilString strFileFn;
+ const MIint nPosColon = m_brkName.find( cColon );
+ if( nPosColon != (MIint) std::string::npos )
+ {
+ CMIUtilString::VecString_t vecFileAndLocation;
+ const MIuint nSplits = m_brkName.Split( cColon, vecFileAndLocation ); MIunused( nSplits );
+ if( vecFileAndLocation.size() != 2 )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_LOCATION_FORMAT ), m_cmdData.strMiCmd.c_str(), m_brkName.c_str() ) );
+ return MIstatus::failure;
+ }
+ fileName = vecFileAndLocation.at( 0 );
+ const CMIUtilString & rStrLineOrFn( vecFileAndLocation.at( 1 ) );
+ if( rStrLineOrFn.empty() )
+ eBrkPtType = eBreakPoint_ByName;
+ else
+ {
+ MIint64 nValue = 0;
+ if( rStrLineOrFn.ExtractNumber( nValue ) )
+ {
+ nFileLine = static_cast< MIuint >( nValue );
+ eBrkPtType = eBreakPoint_ByFileLine;
+ }
+ else
+ {
+ strFileFn = rStrLineOrFn;
+ eBrkPtType = eBreakPoint_ByFileFn;
+ }
+ }
+ }
+
+ // Determine if break defined as an address
+ lldb::addr_t nAddress = 0;
+ if( eBrkPtType == eBreakPoint_NotDefineYet )
+ {
+ MIint64 nValue = 0;
+ if( m_brkName.ExtractNumber( nValue ) )
+ {
+ nAddress = static_cast< lldb::addr_t >( nValue );
+ eBrkPtType = eBreakPoint_ByAddress;
+ }
+ }
+
+ // Break defined as an function
+ if( eBrkPtType == eBreakPoint_NotDefineYet )
+ {
+ eBrkPtType = eBreakPoint_ByName;
+ }
+
+ // Ask LLDB to create a breakpoint
+ bool bOk = MIstatus::success;
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBTarget & rTarget = rSessionInfo.m_lldbTarget;
+ switch( eBrkPtType )
+ {
+ case eBreakPoint_ByAddress:
+ m_brkPt = rTarget.BreakpointCreateByAddress( nAddress );
+ break;
+ case eBreakPoint_ByFileFn:
+ m_brkPt = rTarget.BreakpointCreateByName( strFileFn.c_str(), fileName.c_str() );
+ break;
+ case eBreakPoint_ByFileLine:
+ m_brkPt = rTarget.BreakpointCreateByLocation( fileName.c_str(), nFileLine );
+ break;
+ case eBreakPoint_ByName:
+ m_brkPt = rTarget.BreakpointCreateByName( m_brkName.c_str(), rTarget.GetExecutable().GetFilename() );
+ break;
+ case eBreakPoint_count:
+ case eBreakPoint_NotDefineYet:
+ case eBreakPoint_Invalid:
+ bOk = MIstatus::failure;
+ break;
+ }
+
+ if( bOk )
+ {
+ m_brkPt.SetEnabled( m_bBrkPtEnabled );
+ m_brkPt.SetIgnoreCount( m_nBrkPtIgnoreCount );
+ if( m_bBrkPtCondition )
+ m_brkPt.SetCondition( m_brkPtCondition.c_str() );
+ if( m_bBrkPtThreadId )
+ m_brkPt.SetThreadID( m_nBrkPtThreadId );
+ if( !m_brkPt.IsValid() )
+ m_bBrkPtIsPending = pArgPendingBrkPt->GetFound();
+ }
+
+ // CODETAG_LLDB_BREAKPOINT_CREATION
+ // This is in the main thread
+ // Record break point information to be by LLDB event handler function
+ CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfo;
+ sBrkPtInfo.m_id = m_brkPt.GetID();
+ sBrkPtInfo.m_bDisp = m_bBrkPtIsTemp;
+ sBrkPtInfo.m_bEnabled = m_bBrkPtEnabled;
+ sBrkPtInfo.m_bHaveArgOptionThreadGrp = m_bHaveArgOptionThreadGrp;
+ sBrkPtInfo.m_strOptThrdGrp = m_strArgOptionThreadGrp;
+ sBrkPtInfo.m_strOrigLoc = m_brkName;
+ sBrkPtInfo.m_nIgnore = m_nBrkPtIgnoreCount;
+ sBrkPtInfo.m_bPending = m_bBrkPtIsPending;
+ sBrkPtInfo.m_bCondition = m_bBrkPtCondition;
+ sBrkPtInfo.m_strCondition = m_brkPtCondition;
+ sBrkPtInfo.m_bBrkPtThreadId = m_bBrkPtThreadId;
+ sBrkPtInfo.m_nBrkPtThreadId = m_nBrkPtThreadId;
+ bOk = bOk && rSessionInfo.RecordBrkPtInfo( m_brkPt.GetID(), sBrkPtInfo );
+
+ if( !bOk )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_INVALID ), m_cmdData.strMiCmd.c_str(), m_brkName.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ // CODETAG_LLDB_BRKPT_ID_MAX
+ if( m_brkPt.GetID() > (lldb::break_id_t) rSessionInfo.m_nBrkPointCntMax )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_CNT_EXCEEDED ), m_cmdData.strMiCmd.c_str(), rSessionInfo.m_nBrkPointCntMax, m_brkName.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakInsert::Acknowledge( void )
+{
+ // Get breakpoint information
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfo;
+ if( !rSessionInfo.GetBrkPtInfo( m_brkPt, sBrkPtInfo ) )
+ {
+ return MIstatus::failure;
+ }
+
+ // CODETAG_LLDB_BREAKPOINT_CREATION
+ // Add more breakpoint information or overwrite existing information
+ sBrkPtInfo.m_bDisp = m_bBrkPtIsTemp;
+ sBrkPtInfo.m_bEnabled = m_bBrkPtEnabled;
+ sBrkPtInfo.m_bHaveArgOptionThreadGrp = m_bHaveArgOptionThreadGrp;
+ sBrkPtInfo.m_strOptThrdGrp = m_strArgOptionThreadGrp;
+ sBrkPtInfo.m_nTimes = m_brkPt.GetNumLocations();
+ sBrkPtInfo.m_strOrigLoc = m_brkName;
+ sBrkPtInfo.m_nIgnore = m_nBrkPtIgnoreCount;
+ sBrkPtInfo.m_bPending = m_bBrkPtIsPending;
+ sBrkPtInfo.m_bCondition = m_bBrkPtCondition;
+ sBrkPtInfo.m_strCondition = m_brkPtCondition;
+ sBrkPtInfo.m_bBrkPtThreadId = m_bBrkPtThreadId;
+ sBrkPtInfo.m_nBrkPtThreadId = m_nBrkPtThreadId;
+
+ // MI print "^done,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%08x\",func=\"%s\",file=\"%s\",fullname=\"%s/%s\",line=\"%d\",thread-groups=[\"%s\"],times=\"%d\",original-location=\"%s\"}"
+ CMICmnMIValueTuple miValueTuple;
+ if( !rSessionInfo.MIResponseFormBrkPtInfo( sBrkPtInfo, miValueTuple ) )
+ {
+ return MIstatus::failure;
+ }
+
+ const CMICmnMIValueResult miValueResultD( "bkpt", miValueTuple );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResultD );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdBreakInsert::CreateSelf( void )
+{
+ return new CMICmdCmdBreakInsert();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdBreakDelete constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdBreakDelete::CMICmdCmdBreakDelete( void )
+: m_constStrArgNamedBrkPt( "breakpoint" )
+, m_constStrArgNamedThreadGrp( "thread-group" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "break-delete";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdBreakDelete::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdBreakDelete destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdBreakDelete::~CMICmdCmdBreakDelete( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakDelete::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgNamedThreadGrp, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValListOfN( m_constStrArgNamedBrkPt, true, true, CMICmdArgValListBase::eArgValType_Number ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakDelete::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgBrkPt, ListOfN, m_constStrArgNamedBrkPt );
+
+ // ATM we only handle one break point ID
+ MIuint64 nBrk = UINT64_MAX;
+ if( !pArgBrkPt->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nBrk ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgNamedBrkPt.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ const bool bBrkPt = rSessionInfo.m_lldbTarget.BreakpointDelete( static_cast< lldb::break_id_t >( nBrk ) );
+ if( !bBrkPt )
+ {
+ const CMIUtilString strBrkNum( CMIUtilString::Format( "%d", nBrk ) );
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_INVALID ), m_cmdData.strMiCmd.c_str(), strBrkNum.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakDelete::Acknowledge( void )
+{
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdBreakDelete::CreateSelf( void )
+{
+ return new CMICmdCmdBreakDelete();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdBreakDisable constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdBreakDisable::CMICmdCmdBreakDisable( void )
+: m_constStrArgNamedThreadGrp( "thread-group" )
+, m_constStrArgNamedBrkPt( "breakpoint" )
+, m_bBrkPtDisabledOk( false )
+, m_nBrkPtId( 0 )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "break-disable";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdBreakDisable::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdBreakDisable destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdBreakDisable::~CMICmdCmdBreakDisable( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakDisable::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgNamedThreadGrp, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValListOfN( m_constStrArgNamedBrkPt, true, true, CMICmdArgValListBase::eArgValType_Number ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakDisable::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgBrkPt, ListOfN, m_constStrArgNamedBrkPt );
+
+ // ATM we only handle one break point ID
+ MIuint64 nBrk = UINT64_MAX;
+ if( !pArgBrkPt->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nBrk ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgNamedBrkPt.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID( static_cast< lldb::break_id_t >( nBrk ) );
+ if( brkPt.IsValid() )
+ {
+ m_bBrkPtDisabledOk = true;
+ brkPt.SetEnabled( false );
+ m_nBrkPtId = nBrk;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakDisable::Acknowledge( void )
+{
+ if( m_bBrkPtDisabledOk )
+ {
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "%d", m_nBrkPtId ) );
+ const CMICmnMIValueResult miValueResult( "number", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ const CMICmnMIValueConst miValueConst2( "n" );
+ const CMICmnMIValueResult miValueResult2( "enabled", miValueConst2 );
+ bool bOk = miValueTuple.Add( miValueResult2 );
+ const CMICmnMIValueResult miValueResult3( "bkpt", miValueTuple );
+ const CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_BreakPointModified, miValueResult3 );
+ bOk = bOk && CMICmnStreamStdout::TextToStdout( miOutOfBandRecord.GetString() );
+
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+ return bOk;
+ }
+
+ const CMIUtilString strBrkPtId( CMIUtilString::Format( "%d", m_nBrkPtId ) );
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_INVALID ), strBrkPtId.c_str() ) );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdBreakDisable::CreateSelf( void )
+{
+ return new CMICmdCmdBreakDisable();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdBreakEnable constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdBreakEnable::CMICmdCmdBreakEnable( void )
+: m_constStrArgNamedThreadGrp( "thread-group" )
+, m_constStrArgNamedBrkPt( "breakpoint" )
+, m_bBrkPtEnabledOk( false )
+, m_nBrkPtId( 0 )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "break-enable";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdBreakEnable::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdBreakEnable destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdBreakEnable::~CMICmdCmdBreakEnable( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakEnable::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgNamedThreadGrp, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValListOfN( m_constStrArgNamedBrkPt, true, true, CMICmdArgValListBase::eArgValType_Number ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakEnable::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgBrkPt, ListOfN, m_constStrArgNamedBrkPt );
+
+ // ATM we only handle one break point ID
+ MIuint64 nBrk = UINT64_MAX;
+ if( !pArgBrkPt->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nBrk ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgNamedBrkPt.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID( static_cast< lldb::break_id_t >( nBrk ) );
+ if( brkPt.IsValid() )
+ {
+ m_bBrkPtEnabledOk = true;
+ brkPt.SetEnabled( false );
+ m_nBrkPtId = nBrk;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakEnable::Acknowledge( void )
+{
+ if( m_bBrkPtEnabledOk )
+ {
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "%d", m_nBrkPtId ) );
+ const CMICmnMIValueResult miValueResult( "number", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ const CMICmnMIValueConst miValueConst2( "y" );
+ const CMICmnMIValueResult miValueResult2( "enabled", miValueConst2 );
+ bool bOk = miValueTuple.Add( miValueResult2 );
+ const CMICmnMIValueResult miValueResult3( "bkpt", miValueTuple );
+ const CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_BreakPointModified, miValueResult3 );
+ bOk = bOk && CMICmnStreamStdout::TextToStdout( miOutOfBandRecord.GetString() );
+
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+ return bOk;
+ }
+
+ const CMIUtilString strBrkPtId( CMIUtilString::Format( "%d", m_nBrkPtId ) );
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_INVALID ), strBrkPtId.c_str() ) );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdBreakEnable::CreateSelf( void )
+{
+ return new CMICmdCmdBreakEnable();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdBreakAfter constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdBreakAfter::CMICmdCmdBreakAfter( void )
+: m_constStrArgNamedThreadGrp( "thread-group" )
+, m_constStrArgNamedNumber( "number" )
+, m_constStrArgNamedCount( "count" )
+, m_nBrkPtId( 0 )
+, m_nBrkPtCount( 0 )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "break-after";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdBreakAfter::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdBreakAfter destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdBreakAfter::~CMICmdCmdBreakAfter( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakAfter::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgNamedThreadGrp, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgNamedNumber, true, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgNamedCount, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakAfter::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgNumber, Number, m_constStrArgNamedNumber );
+ CMICMDBASE_GETOPTION( pArgCount, Number, m_constStrArgNamedCount );
+
+ m_nBrkPtId = pArgNumber->GetValue();
+ m_nBrkPtCount = pArgCount->GetValue();
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID( static_cast< lldb::break_id_t >( m_nBrkPtId ) );
+ if( brkPt.IsValid() )
+ {
+ brkPt.SetIgnoreCount( m_nBrkPtCount );
+
+ CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfo;
+ if( !rSessionInfo.RecordBrkPtInfoGet( m_nBrkPtId, sBrkPtInfo ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_INFO_OBJ_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_nBrkPtId ) );
+ return MIstatus::failure;
+ }
+ sBrkPtInfo.m_nIgnore = m_nBrkPtCount;
+ rSessionInfo.RecordBrkPtInfo( m_nBrkPtId, sBrkPtInfo );
+ }
+ else
+ {
+ const CMIUtilString strBrkPtId( CMIUtilString::Format( "%d", m_nBrkPtId ) );
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_INVALID ), m_cmdData.strMiCmd.c_str(), strBrkPtId.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakAfter::Acknowledge( void )
+{
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdBreakAfter::CreateSelf( void )
+{
+ return new CMICmdCmdBreakAfter();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdBreakCondition constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdBreakCondition::CMICmdCmdBreakCondition( void )
+: m_constStrArgNamedThreadGrp( "thread-group" )
+, m_constStrArgNamedNumber( "number" )
+, m_constStrArgNamedExpr( "expr" )
+, m_constStrArgNamedExprNoQuotes( "expression not surround by quotes" ) // Not specified in MI spec, we need to handle expressions not surrounded by quotes
+, m_nBrkPtId( 0 )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "break-condition";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdBreakCondition::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdBreakCondition destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdBreakCondition::~CMICmdCmdBreakCondition( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakCondition::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgNamedThreadGrp, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgNamedNumber, true, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgNamedExpr, true, true, true, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValListOfN( m_constStrArgNamedExprNoQuotes, true, false, CMICmdArgValListBase::eArgValType_StringQuotedNumber ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakCondition::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgNumber, Number, m_constStrArgNamedNumber );
+ CMICMDBASE_GETOPTION( pArgExpr, String, m_constStrArgNamedExpr );
+
+ m_nBrkPtId = pArgNumber->GetValue();
+ m_strBrkPtExpr = pArgExpr->GetValue();
+ m_strBrkPtExpr += GetRestOfExpressionNotSurroundedInQuotes();
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID( static_cast< lldb::break_id_t >( m_nBrkPtId ) );
+ if( brkPt.IsValid() )
+ {
+ brkPt.SetCondition( m_strBrkPtExpr.c_str() );
+
+ CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfo;
+ if( !rSessionInfo.RecordBrkPtInfoGet( m_nBrkPtId, sBrkPtInfo ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_INFO_OBJ_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_nBrkPtId ) );
+ return MIstatus::failure;
+ }
+ sBrkPtInfo.m_strCondition = m_strBrkPtExpr;
+ rSessionInfo.RecordBrkPtInfo( m_nBrkPtId, sBrkPtInfo );
+ }
+ else
+ {
+ const CMIUtilString strBrkPtId( CMIUtilString::Format( "%d", m_nBrkPtId ) );
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_INVALID ), m_cmdData.strMiCmd.c_str(), strBrkPtId.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdBreakCondition::Acknowledge( void )
+{
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdBreakCondition::CreateSelf( void )
+{
+ return new CMICmdCmdBreakCondition();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: A breakpoint expression can be passed to *this command as:
+// a single string i.e. '2' -> ok.
+// a quoted string i.e. "a > 100" -> ok
+// a non quoted string i.e. 'a > 100' -> not ok
+// CMICmdArgValString only extracts the first space seperated string, the "a".
+// This function using the optional argument type CMICmdArgValListOfN collects
+// the rest of the expression so that is may be added to the 'a' part to form a
+// complete expression string i.e. "a > 100".
+// If the expression value was guaranteed to be surrounded by quotes them this
+// function would not be necessary.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Rest of the breakpoint expression.
+// Throws: None.
+//--
+CMIUtilString CMICmdCmdBreakCondition::GetRestOfExpressionNotSurroundedInQuotes( void )
+{
+ CMIUtilString strExpression;
+
+ CMICmdArgValListOfN * pArgExprNoQuotes = CMICmdBase::GetOption< CMICmdArgValListOfN >( m_constStrArgNamedExprNoQuotes );
+ if( pArgExprNoQuotes != nullptr )
+ {
+ CMIUtilString strExpression;
+ const CMICmdArgValListBase::VecArgObjPtr_t & rVecExprParts( pArgExprNoQuotes->GetExpectedOptions() );
+ if( !rVecExprParts.empty() )
+ {
+ CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecExprParts.begin();
+ while( it != rVecExprParts.end() )
+ {
+ const CMICmdArgValString * pPartExpr = static_cast< CMICmdArgValString * >( *it );
+ const CMIUtilString & rPartExpr = pPartExpr->GetValue();
+ strExpression += " ";
+ strExpression += rPartExpr;
+
+ // Next
+ ++it;
+ }
+ strExpression = strExpression.Trim();
+ }
+ }
+
+ return strExpression;
+}
diff --git a/tools/lldb-mi/MICmdCmdBreak.h b/tools/lldb-mi/MICmdCmdBreak.h
new file mode 100644
index 000000000000..e5283d609905
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdBreak.h
@@ -0,0 +1,292 @@
+//===-- MICmdCmdBreak.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdBreak.h
+//
+// Overview: CMICmdCmdBreakInsert interface.
+// CMICmdCmdBreakDelete interface.
+// CMICmdCmdBreakDisable interface.
+// CMICmdCmdBreakEnable interface.
+// CMICmdCmdBreakAfter interface.
+// CMICmdCmdBreakCondition interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <lldb/API/SBBreakpoint.h>
+
+// In-house headers:
+#include "MICmdBase.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "break-insert".
+// This command does not follow the MI documentation exactly.
+// Gotchas: None.
+// Authors: Illya Rudkin 11/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdBreakInsert : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdBreakInsert( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdBreakInsert( void );
+
+// Enumerations:
+private:
+ //++ ===================================================================
+ // Details: The type of break point give in the MI command text.
+ //--
+ enum BreakPoint_e
+ {
+ eBreakPoint_Invalid = 0,
+ eBreakPoint_ByFileLine,
+ eBreakPoint_ByFileFn,
+ eBreakPoint_ByName,
+ eBreakPoint_ByAddress,
+ eBreakPoint_count,
+ eBreakPoint_NotDefineYet
+ };
+
+// Attributes:
+private:
+ bool m_bBrkPtIsTemp;
+ bool m_bHaveArgOptionThreadGrp;
+ CMIUtilString m_brkName;
+ CMIUtilString m_strArgOptionThreadGrp;
+ lldb::SBBreakpoint m_brkPt;
+ bool m_bBrkPtIsPending;
+ MIuint m_nBrkPtIgnoreCount;
+ bool m_bBrkPtEnabled;
+ bool m_bBrkPtCondition;
+ CMIUtilString m_brkPtCondition;
+ bool m_bBrkPtThreadId;
+ MIuint m_nBrkPtThreadId;
+ const CMIUtilString m_constStrArgNamedTempBrkPt;
+ const CMIUtilString m_constStrArgNamedHWBrkPt; // Not handled by *this command
+ const CMIUtilString m_constStrArgNamedPendinfBrkPt;
+ const CMIUtilString m_constStrArgNamedDisableBrkPt;
+ const CMIUtilString m_constStrArgNamedTracePt; // Not handled by *this command
+ const CMIUtilString m_constStrArgNamedConditionalBrkPt;
+ const CMIUtilString m_constStrArgNamedInoreCnt;
+ const CMIUtilString m_constStrArgNamedRestrictBrkPtToThreadId;
+ const CMIUtilString m_constStrArgNamedLocation;
+ const CMIUtilString m_constStrArgNamedThreadGroup; // Not specified in MI spec but Eclipse gives this option sometimes
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "break-delete".
+// Gotchas: None.
+// Authors: Illya Rudkin 11/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdBreakDelete : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdBreakDelete( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdBreakDelete( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgNamedBrkPt;
+ const CMIUtilString m_constStrArgNamedThreadGrp; // Not specified in MI spec but Eclipse gives this option
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "break-disable".
+// Gotchas: None.
+// Authors: Illya Rudkin 19/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdBreakDisable : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdBreakDisable( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdBreakDisable( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgNamedThreadGrp; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgNamedBrkPt;
+ bool m_bBrkPtDisabledOk;
+ MIuint m_nBrkPtId;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "break-enable".
+// Gotchas: None.
+// Authors: Illya Rudkin 19/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdBreakEnable : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdBreakEnable( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdBreakEnable( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgNamedThreadGrp; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgNamedBrkPt;
+ bool m_bBrkPtEnabledOk;
+ MIuint m_nBrkPtId;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "break-after".
+// Gotchas: None.
+// Authors: Illya Rudkin 29/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdBreakAfter : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdBreakAfter( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdBreakAfter( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgNamedThreadGrp; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgNamedNumber;
+ const CMIUtilString m_constStrArgNamedCount;
+ MIuint m_nBrkPtId;
+ MIuint m_nBrkPtCount;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "break-condition".
+// Gotchas: None.
+// Authors: Illya Rudkin 29/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdBreakCondition : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdBreakCondition( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdBreakCondition( void );
+
+// Methods:
+private:
+ CMIUtilString GetRestOfExpressionNotSurroundedInQuotes( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgNamedThreadGrp; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgNamedNumber;
+ const CMIUtilString m_constStrArgNamedExpr;
+ const CMIUtilString m_constStrArgNamedExprNoQuotes; // Not specified in MI spec, we need to handle expressions not surrounded by quotes
+ MIuint m_nBrkPtId;
+ CMIUtilString m_strBrkPtExpr;
+};
diff --git a/tools/lldb-mi/MICmdCmdData.cpp b/tools/lldb-mi/MICmdCmdData.cpp
new file mode 100644
index 000000000000..69012ef042c4
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdData.cpp
@@ -0,0 +1,1365 @@
+//===-- MICmdCmdData.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdData.cpp
+//
+// Overview: CMICmdCmdDataEvaluateExpression implementation.
+// CMICmdCmdDataDisassemble implementation.
+// CMICmdCmdDataReadMemoryBytes implementation.
+// CMICmdCmdDataReadMemory implementation.
+// CMICmdCmdDataListRegisterNames implementation.
+// CMICmdCmdDataListRegisterValues implementation.
+// CMICmdCmdDataListRegisterChanged implementation.
+// CMICmdCmdDataWriteMemoryBytes implementation.
+// CMICmdCmdDataWriteMemory implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third Party Headers:
+#include <lldb/API/SBThread.h>
+#include <lldb/API/SBInstruction.h>
+#include <lldb/API/SBInstructionList.h>
+#include <lldb/API/SBStream.h>
+
+// In-house headers:
+#include "MICmdCmdData.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnLLDBDebugger.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MICmnLLDBProxySBValue.h"
+#include "MICmdArgValNumber.h"
+#include "MICmdArgValString.h"
+#include "MICmdArgValThreadGrp.h"
+#include "MICmdArgValOptionLong.h"
+#include "MICmdArgValOptionShort.h"
+#include "MICmdArgValListOfN.h"
+#include "MICmdArgValConsume.h"
+#include "MICmnLLDBDebugSessionInfoVarObj.h"
+#include "MICmnLLDBUtilSBValue.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataEvaluateExpression constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataEvaluateExpression::CMICmdCmdDataEvaluateExpression( void )
+: m_bExpressionValid( true )
+, m_bEvaluatedExpression( true )
+, m_strValue( "??" )
+, m_bCompositeVarType( false )
+, m_bFoundInvalidChar( false )
+, m_cExpressionInvalidChar( 0x00 )
+, m_constStrArgThread( "thread" )
+, m_constStrArgFrame( "frame" )
+, m_constStrArgExpr( "expr" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "data-evaluate-expression";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdDataEvaluateExpression::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataEvaluateExpression destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataEvaluateExpression::~CMICmdCmdDataEvaluateExpression( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataEvaluateExpression::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgFrame, false, false, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgExpr, true, true, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataEvaluateExpression::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgExpr, String, m_constStrArgExpr );
+
+ const CMIUtilString & rExpression( pArgExpr->GetValue() );
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+ lldb::SBThread thread = rProcess.GetSelectedThread();
+ m_bExpressionValid = (thread.GetNumFrames() > 0);
+ if( !m_bExpressionValid )
+ return MIstatus::success;
+
+ lldb::SBFrame frame = thread.GetSelectedFrame();
+ lldb::SBValue value = frame.EvaluateExpression( rExpression.c_str() );
+ if( !value.IsValid() )
+ value = frame.FindVariable( rExpression.c_str() );
+ if( !value.IsValid() )
+ {
+ m_bEvaluatedExpression = false;
+ return MIstatus::success;
+ }
+ const CMICmnLLDBUtilSBValue utilValue( value );
+ if( !utilValue.HasName() )
+ {
+ if( HaveInvalidCharacterInExpression( rExpression, m_cExpressionInvalidChar ) )
+ {
+ m_bFoundInvalidChar = true;
+ return MIstatus::success;
+ }
+
+ m_strValue = rExpression;
+ return MIstatus::success;
+ }
+ if( rExpression.IsQuoted() )
+ {
+ m_strValue = rExpression.Trim( '\"' );
+ return MIstatus::success;
+ }
+
+ MIuint64 nNumber = 0;
+ if( CMICmnLLDBProxySBValue::GetValueAsUnsigned( value, nNumber ) == MIstatus::success )
+ {
+ const lldb::ValueType eValueType = value.GetValueType(); MIunused( eValueType );
+ m_strValue = utilValue.GetValue();
+ CMIUtilString strCString;
+ if( CMICmnLLDBProxySBValue::GetCString( value, strCString ) )
+ {
+ m_strValue += CMIUtilString::Format( " '%s'", strCString.c_str() );
+ }
+ return MIstatus::success;
+ }
+
+ // Composite type i.e. struct
+ m_bCompositeVarType = true;
+ const MIuint nChild = value.GetNumChildren();
+ for( MIuint i = 0; i < nChild; i++ )
+ {
+ lldb::SBValue member = value.GetChildAtIndex( i );
+ const bool bValid = member.IsValid();
+ CMIUtilString strType( MIRSRC( IDS_WORD_UNKNOWNTYPE_BRKTS ) );
+ if( bValid )
+ {
+ const CMIUtilString strValue( CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted( member, CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Natural ) );
+ const char * pTypeName = member.GetName();
+ if( pTypeName != nullptr )
+ strType = pTypeName;
+
+ // MI print "{variable = 1, variable2 = 3, variable3 = 5}"
+ const bool bNoQuotes = true;
+ const CMICmnMIValueConst miValueConst( strValue, bNoQuotes );
+ const bool bUseSpaces = true;
+ const CMICmnMIValueResult miValueResult( strType, miValueConst, bUseSpaces );
+ m_miValueTuple.Add( miValueResult, bUseSpaces );
+ }
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataEvaluateExpression::Acknowledge( void )
+{
+ if( m_bExpressionValid )
+ {
+ if( m_bEvaluatedExpression )
+ {
+ if( m_bCompositeVarType )
+ {
+ const CMICmnMIValueConst miValueConst( m_miValueTuple.GetString() );
+ const CMICmnMIValueResult miValueResult( "value", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ if( m_bFoundInvalidChar )
+ {
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "Invalid character '%c' in expression", m_cExpressionInvalidChar ) );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ const CMICmnMIValueConst miValueConst( m_strValue );
+ const CMICmnMIValueResult miValueResult( "value", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ const CMICmnMIValueConst miValueConst( "Could not evaluate expression" );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ const CMICmnMIValueConst miValueConst( "Invalid expression" );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdDataEvaluateExpression::CreateSelf( void )
+{
+ return new CMICmdCmdDataEvaluateExpression();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Examine the expression string to see if it contains invalid characters.
+// Type: Method.
+// Args: vrExpr - (R) Expression string given to *this command.
+// vrwInvalidChar - (W) True = Invalid character found, false = nothing found.
+// Return: bool - True = Invalid character found, false = nothing found.
+// Throws: None.
+//--
+bool CMICmdCmdDataEvaluateExpression::HaveInvalidCharacterInExpression( const CMIUtilString & vrExpr, MIchar & vrwInvalidChar )
+{
+ bool bFoundInvalidCharInExpression = false;
+ vrwInvalidChar = 0x00;
+
+ if( vrExpr.at( 0 ) == '\\' )
+ {
+ // Example: Mouse hover over "%5d" expression has \"%5d\" in it
+ bFoundInvalidCharInExpression = true;
+ vrwInvalidChar = '\\';
+ }
+
+ return bFoundInvalidCharInExpression;
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataDisassemble constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataDisassemble::CMICmdCmdDataDisassemble( void )
+: m_constStrArgThread( "thread" )
+, m_constStrArgAddrStart( "s" )
+, m_constStrArgAddrEnd( "e" )
+, m_constStrArgConsume( "--" )
+, m_constStrArgMode( "mode" )
+, m_miValueList( true )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "data-disassemble";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdDataDisassemble::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataDisassemble destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataDisassemble::~CMICmdCmdDataDisassemble( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataDisassemble::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgAddrStart, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgAddrEnd, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValConsume( m_constStrArgConsume, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgMode, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataDisassemble::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
+ CMICMDBASE_GETOPTION( pArgAddrStart, OptionShort, m_constStrArgAddrStart );
+ CMICMDBASE_GETOPTION( pArgAddrEnd, OptionShort, m_constStrArgAddrEnd );
+ CMICMDBASE_GETOPTION( pArgMode, Number, m_constStrArgMode );
+
+ // Retrieve the --thread option's thread ID (only 1)
+ MIuint64 nThreadId = UINT64_MAX;
+ if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_THREAD_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
+ return MIstatus::failure;
+ }
+ CMIUtilString strAddrStart;
+ if( !pArgAddrStart->GetExpectedOption< CMICmdArgValString, CMIUtilString >( strAddrStart ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_DISASM_ADDR_START_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrStart.c_str() ) );
+ return MIstatus::failure;
+ }
+ MIint64 nAddrStart = 0;
+ if( !strAddrStart.ExtractNumber( nAddrStart ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_DISASM_ADDR_START_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrStart.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMIUtilString strAddrEnd;
+ if( !pArgAddrEnd->GetExpectedOption< CMICmdArgValString, CMIUtilString >( strAddrEnd ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_DISASM_ADDR_END_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrEnd.c_str() ) );
+ return MIstatus::failure;
+ }
+ MIint64 nAddrEnd = 0;
+ if( !strAddrEnd.ExtractNumber( nAddrEnd ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_DISASM_ADDR_END_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrEnd.c_str() ) );
+ return MIstatus::failure;
+ }
+ const MIuint nDisasmMode = pArgMode->GetValue();
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBTarget & rTarget = rSessionInfo.m_lldbTarget;
+ lldb::addr_t lldbStartAddr = static_cast< lldb::addr_t >( nAddrStart );
+ lldb::SBInstructionList instructions = rTarget.ReadInstructions( lldb::SBAddress( lldbStartAddr, rTarget ), nAddrEnd - nAddrStart );
+ const MIuint nInstructions = instructions.GetSize();
+ for( size_t i = 0; i < nInstructions; i++ )
+ {
+ const MIchar * pUnknown = "??";
+ lldb::SBInstruction instrt = instructions.GetInstructionAtIndex( i );
+ const MIchar * pStrMnemonic = instrt.GetMnemonic( rTarget );
+ pStrMnemonic = (pStrMnemonic != nullptr) ? pStrMnemonic : pUnknown;
+ lldb::SBAddress address = instrt.GetAddress();
+ lldb::addr_t addr = address.GetLoadAddress( rTarget );
+ const MIchar * pFnName = address.GetFunction().GetName();
+ pFnName = (pFnName != nullptr) ? pFnName : pUnknown;
+ lldb::addr_t addrOffSet = address.GetOffset();
+ const MIchar * pStrOperands = instrt.GetOperands( rTarget );
+ pStrOperands = (pStrOperands != nullptr) ? pStrOperands : pUnknown;
+
+ // MI "{address=\"0x%08llx\",func-name=\"%s\",offset=\"%lld\",inst=\"%s %s\"}"
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "0x%08llx", addr ) );
+ const CMICmnMIValueResult miValueResult( "address", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ const CMICmnMIValueConst miValueConst2( pFnName );
+ const CMICmnMIValueResult miValueResult2( "func-name", miValueConst2 );
+ miValueTuple.Add( miValueResult2 );
+ const CMICmnMIValueConst miValueConst3( CMIUtilString::Format( "0x%lld", addrOffSet ) );
+ const CMICmnMIValueResult miValueResult3( "offset", miValueConst3 );
+ miValueTuple.Add( miValueResult3 );
+ const CMICmnMIValueConst miValueConst4( CMIUtilString::Format( "%s %s", pStrMnemonic, pStrOperands ) );
+ const CMICmnMIValueResult miValueResult4( "inst", miValueConst4 );
+ miValueTuple.Add( miValueResult4 );
+
+ if( nDisasmMode == 1 )
+ {
+ lldb::SBLineEntry lineEntry = address.GetLineEntry();
+ const MIuint nLine = lineEntry.GetLine();
+ const MIchar * pFileName = lineEntry.GetFileSpec().GetFilename();
+ pFileName = (pFileName != nullptr) ? pFileName : pUnknown;
+
+ // MI "src_and_asm_line={line=\"%u\",file=\"%s\",line_asm_insn=[ ]}"
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "0x%u", nLine ) );
+ const CMICmnMIValueResult miValueResult( "line", miValueConst );
+ CMICmnMIValueTuple miValueTuple2( miValueResult );
+ const CMICmnMIValueConst miValueConst2( pFileName );
+ const CMICmnMIValueResult miValueResult2( "file", miValueConst2 );
+ miValueTuple2.Add( miValueResult2 );
+ const CMICmnMIValueList miValueList( miValueTuple );
+ const CMICmnMIValueResult miValueResult3( "line_asm_insn", miValueList );
+ miValueTuple2.Add( miValueResult3 );
+ const CMICmnMIValueResult miValueResult4( "src_and_asm_line", miValueTuple2 );
+ m_miValueList.Add( miValueResult4 );
+ }
+ else
+ {
+ m_miValueList.Add( miValueTuple );
+ }
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataDisassemble::Acknowledge( void )
+{
+ const CMICmnMIValueResult miValueResult( "asm_insns", m_miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdDataDisassemble::CreateSelf( void )
+{
+ return new CMICmdCmdDataDisassemble();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataReadMemoryBytes constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataReadMemoryBytes::CMICmdCmdDataReadMemoryBytes( void )
+: m_constStrArgThread( "thread" )
+, m_constStrArgByteOffset( "o" )
+, m_constStrArgAddrStart( "address" )
+, m_constStrArgNumBytes( "count" )
+, m_pBufferMemory( nullptr )
+, m_nAddrStart( 0 )
+, m_nAddrNumBytesToRead( 0 )
+, m_nAddrOffset( 0 )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "data-read-memory-bytes";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdDataReadMemoryBytes::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataReadMemoryBytes destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataReadMemoryBytes::~CMICmdCmdDataReadMemoryBytes( void )
+{
+ if( m_pBufferMemory != nullptr )
+ {
+ delete [] m_pBufferMemory;
+ m_pBufferMemory = nullptr;
+ }
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataReadMemoryBytes::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgByteOffset, false, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgAddrStart, true, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgNumBytes, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataReadMemoryBytes::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgAddrStart, Number, m_constStrArgAddrStart );
+ CMICMDBASE_GETOPTION( pArgAddrOffset, Number, m_constStrArgByteOffset );
+ CMICMDBASE_GETOPTION( pArgNumBytes, Number, m_constStrArgNumBytes );
+
+ const MIuint64 nAddrStart = pArgAddrStart->GetValue();
+ const MIuint64 nAddrNumBytes = pArgNumBytes->GetValue();
+ if( pArgAddrOffset->GetFound() )
+ m_nAddrOffset = pArgAddrOffset->GetValue();
+
+ m_pBufferMemory = new MIuchar[ nAddrNumBytes ];
+ if( m_pBufferMemory == nullptr )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_MEMORY_ALLOC_FAILURE ), m_cmdData.strMiCmd.c_str(), nAddrNumBytes ) );
+ return MIstatus::failure;
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+ lldb::SBError error;
+ const MIuint64 nReadBytes = rProcess.ReadMemory( static_cast< lldb::addr_t >( nAddrStart ), (void *) m_pBufferMemory, nAddrNumBytes, error );
+ if( nReadBytes != nAddrNumBytes )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_LLDB_ERR_NOT_READ_WHOLE_BLK ), m_cmdData.strMiCmd.c_str(), nAddrNumBytes, nAddrStart ) );
+ return MIstatus::failure;
+ }
+ if( error.Fail() )
+ {
+ lldb::SBStream err;
+ const bool bOk = error.GetDescription( err ); MIunused( bOk );
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES ), m_cmdData.strMiCmd.c_str(), nAddrNumBytes, nAddrStart, err.GetData() ) );
+ return MIstatus::failure;
+ }
+
+ m_nAddrStart = nAddrStart;
+ m_nAddrNumBytesToRead = nAddrNumBytes;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataReadMemoryBytes::Acknowledge( void )
+{
+ // MI: memory=[{begin=\"0x%08x\",offset=\"0x%08x\",end=\"0x%08x\",contents=\" \" }]"
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "0x%08x", m_nAddrStart ) );
+ const CMICmnMIValueResult miValueResult( "begin", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ const CMICmnMIValueConst miValueConst2( CMIUtilString::Format( "0x%08x", m_nAddrOffset ) );
+ const CMICmnMIValueResult miValueResult2( "offset", miValueConst2 );
+ miValueTuple.Add( miValueResult2 );
+ const CMICmnMIValueConst miValueConst3( CMIUtilString::Format( "0x%08x", m_nAddrStart + m_nAddrNumBytesToRead ) );
+ const CMICmnMIValueResult miValueResult3( "end", miValueConst3 );
+ miValueTuple.Add( miValueResult3 );
+
+ // MI: contents=\" \"
+ CMIUtilString strContent;
+ strContent.reserve( (m_nAddrNumBytesToRead << 1) + 1 );
+ for( MIuint64 i = 0; i < m_nAddrNumBytesToRead; i ++ )
+ {
+ strContent += CMIUtilString::Format( "%02x", m_pBufferMemory[ i ] );
+ }
+ const CMICmnMIValueConst miValueConst4( strContent );
+ const CMICmnMIValueResult miValueResult4( "contents", miValueConst4 );
+ miValueTuple.Add( miValueResult4 );
+ const CMICmnMIValueList miValueList( miValueTuple );
+ const CMICmnMIValueResult miValueResult5( "memory", miValueList );
+
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult5 );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdDataReadMemoryBytes::CreateSelf( void )
+{
+ return new CMICmdCmdDataReadMemoryBytes();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataReadMemory constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataReadMemory::CMICmdCmdDataReadMemory( void )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "data-read-memory";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdDataReadMemory::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataReadMemory destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataReadMemory::~CMICmdCmdDataReadMemory( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataReadMemory::Execute( void )
+{
+ // Do nothing - command deprecated use "data-read-memory-bytes" command
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataReadMemory::Acknowledge( void )
+{
+ // Command CMICmdCmdSupportListFeatures sends "data-read-memory-bytes" which causes this command not to be called
+ const CMICmnMIValueConst miValueConst( MIRSRC( IDS_CMD_ERR_NOT_IMPLEMENTED_DEPRECATED ) );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdDataReadMemory::CreateSelf( void )
+{
+ return new CMICmdCmdDataReadMemory();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataListRegisterNames constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataListRegisterNames::CMICmdCmdDataListRegisterNames( void )
+: m_constStrArgThreadGroup( "thread-group" )
+, m_constStrArgRegNo( "regno" )
+, m_miValueList( true )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "data-list-register-names";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdDataListRegisterNames::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataReadMemoryBytes destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataListRegisterNames::~CMICmdCmdDataListRegisterNames( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataListRegisterNames::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThreadGroup, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValListOfN( m_constStrArgRegNo, false, false, CMICmdArgValListBase::eArgValType_Number ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataListRegisterNames::Execute( void )
+{
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+ if( !rProcess.IsValid() )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_PROCESS ), m_cmdData.strMiCmd.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ lldb::SBThread thread = rProcess.GetSelectedThread();
+ lldb::SBFrame frame = thread.GetSelectedFrame();
+ lldb::SBValueList registers = frame.GetRegisters();
+ const MIuint nRegisters = registers.GetSize();
+ for( MIuint i = 0; i < nRegisters; i++ )
+ {
+ lldb::SBValue value = registers.GetValueAtIndex( i );
+ const MIuint nRegChildren = value.GetNumChildren();
+ for( MIuint j = 0; j < nRegChildren; j++ )
+ {
+ lldb::SBValue value2 = value.GetChildAtIndex( j );
+ if( value2.IsValid() )
+ {
+ const CMICmnMIValueConst miValueConst( CMICmnLLDBUtilSBValue( value2 ).GetName() );
+ m_miValueList.Add( miValueConst );
+ }
+ }
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataListRegisterNames::Acknowledge( void )
+{
+ const CMICmnMIValueResult miValueResult( "register-names", m_miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdDataListRegisterNames::CreateSelf( void )
+{
+ return new CMICmdCmdDataListRegisterNames();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataListRegisterValues constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataListRegisterValues::CMICmdCmdDataListRegisterValues( void )
+: m_constStrArgThread( "thread" )
+, m_constStrArgSkip( "skip-unavailable" )
+, m_constStrArgFormat( "fmt" )
+, m_constStrArgRegNo( "regno" )
+, m_miValueList( true )
+, m_pProcess( nullptr )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "data-list-register-values";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdDataListRegisterValues::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataListRegisterValues destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataListRegisterValues::~CMICmdCmdDataListRegisterValues( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataListRegisterValues::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgSkip, false, false ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgFormat, true, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValListOfN( m_constStrArgRegNo, false, true, CMICmdArgValListBase::eArgValType_Number ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataListRegisterValues::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgFormat, String, m_constStrArgFormat );
+ CMICMDBASE_GETOPTION( pArgRegNo, ListOfN, m_constStrArgRegNo );
+
+ const CMIUtilString & rStrFormat( pArgFormat->GetValue() );
+ if( rStrFormat.length() != 1 )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_FORMAT_TYPE ), m_cmdData.strMiCmd.c_str(), rStrFormat.c_str() ) );
+ return MIstatus::failure;
+ }
+ const CMICmnLLDBDebugSessionInfoVarObj::varFormat_e eFormat = CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForChar( rStrFormat[ 0 ] );
+ if( eFormat == CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Invalid )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_FORMAT_TYPE ), m_cmdData.strMiCmd.c_str(), rStrFormat.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+ if( !rProcess.IsValid() )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_PROCESS ), m_cmdData.strMiCmd.c_str() ) );
+ return MIstatus::failure;
+ }
+ m_pProcess = &rProcess;
+
+ const CMICmdArgValListBase::VecArgObjPtr_t & rVecRegNo( pArgRegNo->GetExpectedOptions() );
+ CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin();
+ while( it != rVecRegNo.end() )
+ {
+ const CMICmdArgValNumber * pRegNo = static_cast< CMICmdArgValNumber * >( *it );
+ const MIuint nReg = pRegNo->GetValue();
+ lldb::SBValue regValue = GetRegister( nReg );
+ const CMIUtilString strRegValue( CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted( regValue, eFormat ) );
+
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "%u", nReg ) );
+ const CMICmnMIValueResult miValueResult( "number", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ const CMICmnMIValueConst miValueConst2( strRegValue );
+ const CMICmnMIValueResult miValueResult2( "value", miValueConst2 );
+ miValueTuple.Add( miValueResult2 );
+ m_miValueList.Add( miValueTuple );
+
+ // Next
+ ++it;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataListRegisterValues::Acknowledge( void )
+{
+ const CMICmnMIValueResult miValueResult( "register-values", m_miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdDataListRegisterValues::CreateSelf( void )
+{
+ return new CMICmdCmdDataListRegisterValues();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Method.
+// Args: None.
+// Return: lldb::SBValue - LLDB SBValue object.
+// Throws: None.
+//--
+lldb::SBValue CMICmdCmdDataListRegisterValues::GetRegister( const MIuint vRegisterIndex ) const
+{
+ lldb::SBThread thread = m_pProcess->GetSelectedThread();
+ lldb::SBFrame frame = thread.GetSelectedFrame();
+ lldb::SBValueList registers = frame.GetRegisters();
+ const MIuint nRegisters = registers.GetSize();
+ for( MIuint i = 0; i < nRegisters; i++ )
+ {
+ lldb::SBValue value = registers.GetValueAtIndex( i );
+ const MIuint nRegChildren = value.GetNumChildren();
+ if( nRegChildren > 0 )
+ {
+ lldb::SBValue value2 = value.GetChildAtIndex( vRegisterIndex );
+ if( value2.IsValid() )
+ {
+ return value2;
+ }
+ }
+ }
+
+ return lldb::SBValue();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataListRegisterChanged constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataListRegisterChanged::CMICmdCmdDataListRegisterChanged( void )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "data-list-changed-registers";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdDataListRegisterChanged::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataListRegisterChanged destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataListRegisterChanged::~CMICmdCmdDataListRegisterChanged( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataListRegisterChanged::Execute( void )
+{
+ // Do nothing
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataListRegisterChanged::Acknowledge( void )
+{
+ const CMICmnMIValueConst miValueConst( MIRSRC( IDS_WORD_NOT_IMPLEMENTED ) );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdDataListRegisterChanged::CreateSelf( void )
+{
+ return new CMICmdCmdDataListRegisterChanged();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataWriteMemoryBytes constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataWriteMemoryBytes::CMICmdCmdDataWriteMemoryBytes( void )
+: m_constStrArgThread( "thread" )
+, m_constStrArgAddr( "address" )
+, m_constStrArgContents( "contents" )
+, m_constStrArgCount( "count" )
+, m_nAddr( 0 )
+, m_nCount( 0 )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "data-write-memory-bytes";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdDataWriteMemoryBytes::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataWriteMemoryBytes destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataWriteMemoryBytes::~CMICmdCmdDataWriteMemoryBytes( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataWriteMemoryBytes::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgAddr, true, true, false, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgContents, true, true, true, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgCount, false, true, false, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataWriteMemoryBytes::Execute( void )
+{
+ // Do nothing - not reproduceable (yet) in Eclipse
+ //CMICMDBASE_GETOPTION( pArgOffset, OptionShort, m_constStrArgOffset );
+ //CMICMDBASE_GETOPTION( pArgAddr, String, m_constStrArgAddr );
+ //CMICMDBASE_GETOPTION( pArgNumber, String, m_constStrArgNumber );
+ //CMICMDBASE_GETOPTION( pArgContents, String, m_constStrArgContents );
+ //
+ // Numbers extracts as string types as they could be hex numbers
+ // '&' is not recognised and so has to be removed
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataWriteMemoryBytes::Acknowledge( void )
+{
+ const CMICmnMIValueConst miValueConst( MIRSRC( IDS_WORD_NOT_IMPLEMENTED ) );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdDataWriteMemoryBytes::CreateSelf( void )
+{
+ return new CMICmdCmdDataWriteMemoryBytes();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataWriteMemory constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataWriteMemory::CMICmdCmdDataWriteMemory( void )
+: m_constStrArgThread( "thread" )
+, m_constStrArgOffset( "o" )
+, m_constStrArgAddr( "address" )
+, m_constStrArgD( "d" )
+, m_constStrArgNumber( "a number" )
+, m_constStrArgContents( "contents" )
+, m_nAddr( 0 )
+, m_nCount( 0 )
+, m_pBufferMemory( nullptr )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "data-write-memory";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdDataWriteMemory::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdDataWriteMemory destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdDataWriteMemory::~CMICmdCmdDataWriteMemory( void )
+{
+ if( m_pBufferMemory != nullptr )
+ {
+ delete [] m_pBufferMemory;
+ m_pBufferMemory = nullptr;
+ }
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataWriteMemory::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgOffset, false, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgAddr, true, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgD, true, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgNumber, true, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgContents, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataWriteMemory::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgOffset, OptionShort, m_constStrArgOffset );
+ CMICMDBASE_GETOPTION( pArgAddr, Number, m_constStrArgAddr );
+ CMICMDBASE_GETOPTION( pArgNumber, Number, m_constStrArgNumber );
+ CMICMDBASE_GETOPTION( pArgContents, Number, m_constStrArgContents );
+
+ MIuint nAddrOffset = 0;
+ if( pArgOffset->GetFound() && !pArgOffset->GetExpectedOption< CMICmdArgValNumber, MIuint>( nAddrOffset ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ARGS_ERR_VALIDATION_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgAddr.c_str() ) );
+ return MIstatus::failure;
+ }
+ m_nAddr = pArgAddr->GetValue();
+ m_nCount = pArgNumber->GetValue();
+ const MIuint64 nValue = pArgContents->GetValue();
+
+ m_pBufferMemory = new MIuchar [ m_nCount ];
+ if( m_pBufferMemory == nullptr )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_MEMORY_ALLOC_FAILURE ), m_cmdData.strMiCmd.c_str(), m_nCount ) );
+ return MIstatus::failure;
+ }
+ *m_pBufferMemory = static_cast< MIchar >( nValue );
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+ lldb::SBError error;
+ lldb::addr_t addr = static_cast< lldb::addr_t >( m_nAddr + nAddrOffset );
+ const size_t nBytesWritten = rProcess.WriteMemory( addr, (const void *) m_pBufferMemory, (size_t) m_nCount, error );
+ if( nBytesWritten != static_cast< size_t >( m_nCount ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_LLDB_ERR_NOT_WRITE_WHOLEBLK ), m_cmdData.strMiCmd.c_str(), m_nCount, addr ) );
+ return MIstatus::failure;
+ }
+ if( error.Fail() )
+ {
+ lldb::SBStream err;
+ const bool bOk = error.GetDescription( err ); MIunused( bOk );
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_LLDB_ERR_WRITE_MEM_BYTES ), m_cmdData.strMiCmd.c_str(), m_nCount, addr, err.GetData() ) );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdDataWriteMemory::Acknowledge( void )
+{
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdDataWriteMemory::CreateSelf( void )
+{
+ return new CMICmdCmdDataWriteMemory();
+}
diff --git a/tools/lldb-mi/MICmdCmdData.h b/tools/lldb-mi/MICmdCmdData.h
new file mode 100644
index 000000000000..c1501de3918f
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdData.h
@@ -0,0 +1,374 @@
+//===-- MICmdCmdData.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdData.h
+//
+// Overview: CMICmdCmdDataEvaluateExpression interface.
+// CMICmdCmdDataDisassemble interface.
+// CMICmdCmdDataReadMemoryBytes interface.
+// CMICmdCmdDataReadMemory interface.
+// CMICmdCmdDataListRegisterNames interface.
+// CMICmdCmdDataListRegisterValues interface.
+// CMICmdCmdDataListRegisterChanged interface.
+// CMICmdCmdDataWriteMemoryBytes interface.
+// CMICmdCmdDataWriteMemory interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdBase.h"
+#include "MICmnMIValueTuple.h"
+#include "MICmnMIValueList.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "data-evaluate-expression".
+// Gotchas: None.
+// Authors: Illya Rudkin 26/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdDataEvaluateExpression : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdDataEvaluateExpression( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdDataEvaluateExpression( void );
+
+// Methods:
+private:
+ bool HaveInvalidCharacterInExpression( const CMIUtilString & vrExpr, MIchar & vrwInvalidChar );
+
+// Attributes:
+private:
+ bool m_bExpressionValid; // True = yes is valid, false = not valid
+ bool m_bEvaluatedExpression; // True = yes is expression evaluated, false = failed
+ CMIUtilString m_strValue;
+ CMICmnMIValueTuple m_miValueTuple;
+ bool m_bCompositeVarType; // True = yes composite type, false = internal type
+ bool m_bFoundInvalidChar; // True = yes found unexpected character in the expression, false = all ok
+ MIchar m_cExpressionInvalidChar;
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option. Not handled by command.
+ const CMIUtilString m_constStrArgFrame; // Not specified in MI spec but Eclipse gives this option. Not handled by command.
+ const CMIUtilString m_constStrArgExpr;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "data-disassemble".
+// Gotchas: None.
+// Authors: Illya Rudkin 19/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdDataDisassemble : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdDataDisassemble( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdDataDisassemble( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option. Not handled by command.
+ const CMIUtilString m_constStrArgAddrStart; // MI spec non mandatory, *this command mandatory
+ const CMIUtilString m_constStrArgAddrEnd; // MI spec non mandatory, *this command mandatory
+ const CMIUtilString m_constStrArgConsume;
+ const CMIUtilString m_constStrArgMode;
+ CMICmnMIValueList m_miValueList;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "data-read-memory-bytes".
+// Gotchas: None.
+// Authors: Illya Rudkin 20/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdDataReadMemoryBytes : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdDataReadMemoryBytes( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdDataReadMemoryBytes( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option. Not handled by command.
+ const CMIUtilString m_constStrArgByteOffset;
+ const CMIUtilString m_constStrArgAddrStart;
+ const CMIUtilString m_constStrArgNumBytes;
+ MIuchar * m_pBufferMemory;
+ MIuint64 m_nAddrStart;
+ MIuint64 m_nAddrNumBytesToRead;
+ MIuint64 m_nAddrOffset;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "data-read-memory".
+// Gotchas: None.
+// Authors: Illya Rudkin 21/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdDataReadMemory : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdDataReadMemory( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdDataReadMemory( void );
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "data-list-register-names".
+// Gotchas: None.
+// Authors: Illya Rudkin 21/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdDataListRegisterNames : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdDataListRegisterNames( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdDataListRegisterNames( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgThreadGroup; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgRegNo; // Not handled by *this command
+ CMICmnMIValueList m_miValueList;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "data-list-register-values".
+// Gotchas: None.
+// Authors: Illya Rudkin 21/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdDataListRegisterValues : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdDataListRegisterValues( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdDataListRegisterValues( void );
+
+// Methods:
+private:
+ lldb::SBValue GetRegister( const MIuint vRegisterIndex ) const;
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgSkip; // Not handled by *this command
+ const CMIUtilString m_constStrArgFormat;
+ const CMIUtilString m_constStrArgRegNo;
+ CMICmnMIValueList m_miValueList;
+ lldb::SBProcess * m_pProcess;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "data-list-changed-registers".
+// Gotchas: None.
+// Authors: Illya Rudkin 22/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdDataListRegisterChanged : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdDataListRegisterChanged( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdDataListRegisterChanged( void );
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "data-read-memory-bytes".
+// Gotchas: None.
+// Authors: Illya Rudkin 30/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdDataWriteMemoryBytes : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdDataWriteMemoryBytes( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdDataWriteMemoryBytes( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option. Not handled by command.
+ const CMIUtilString m_constStrArgAddr;
+ const CMIUtilString m_constStrArgContents;
+ const CMIUtilString m_constStrArgCount;
+ MIuint64 m_nAddr;
+ CMIUtilString m_strContents;
+ MIuint64 m_nCount;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "data-read-memory".
+// Not specified in MI spec but Eclipse gives *this command.
+// Gotchas: None.
+// Authors: Illya Rudkin 02/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdDataWriteMemory : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdDataWriteMemory( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdDataWriteMemory( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option. Not handled by command.
+ const CMIUtilString m_constStrArgOffset; // Not specified in MI spec but Eclipse gives this option.
+ const CMIUtilString m_constStrArgAddr; // Not specified in MI spec but Eclipse gives this option.
+ const CMIUtilString m_constStrArgD; // Not specified in MI spec but Eclipse gives this option.
+ const CMIUtilString m_constStrArgNumber; // Not specified in MI spec but Eclipse gives this option.
+ const CMIUtilString m_constStrArgContents; // Not specified in MI spec but Eclipse gives this option.
+ MIuint64 m_nAddr;
+ CMIUtilString m_strContents;
+ MIuint64 m_nCount;
+ MIuchar * m_pBufferMemory;
+}; \ No newline at end of file
diff --git a/tools/lldb-mi/MICmdCmdEnviro.cpp b/tools/lldb-mi/MICmdCmdEnviro.cpp
new file mode 100644
index 000000000000..b47327af9406
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdEnviro.cpp
@@ -0,0 +1,143 @@
+//===-- MICmdCmdEnviro.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdEnviro.cpp
+//
+// Overview: CMICmdCmdEnvironmentCd implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdCmdEnviro.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnLLDBDebugger.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MICmdArgValFile.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdEnvironmentCd constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdEnvironmentCd::CMICmdCmdEnvironmentCd( void )
+: m_constStrArgNamePathDir( "pathdir" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "environment-cd";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdEnvironmentCd::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdEnvironmentCd destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdEnvironmentCd::~CMICmdCmdEnvironmentCd( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdEnvironmentCd::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValFile( m_constStrArgNamePathDir, true, true ) ) );
+ CMICmdArgContext argCntxt( m_cmdData.strMiCmdOption );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdEnvironmentCd::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgPathDir, File, m_constStrArgNamePathDir );
+ const CMIUtilString & strWkDir( pArgPathDir->GetValue() );
+ CMICmnLLDBDebugger & rDbg( CMICmnLLDBDebugger::Instance() );
+ lldb::SBDebugger & rLldbDbg = rDbg.GetTheDebugger();
+ bool bOk = rLldbDbg.SetCurrentPlatformSDKRoot( strWkDir.c_str() );
+ if( bOk )
+ {
+ const CMIUtilString & rStrKeyWkDir( m_rLLDBDebugSessionInfo.m_constStrSharedDataKeyWkDir );
+ if( !m_rLLDBDebugSessionInfo.SharedDataAdd< CMIUtilString >( rStrKeyWkDir, strWkDir ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_DBGSESSION_ERR_SHARED_DATA_ADD ), m_cmdData.strMiCmd.c_str(), rStrKeyWkDir.c_str() ) );
+ bOk = MIstatus::failure;
+ }
+ }
+ else
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_FNFAILED ), m_cmdData.strMiCmd.c_str(), "SetCurrentPlatformSDKRoot()" ) );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdEnvironmentCd::Acknowledge( void )
+{
+ const CMIUtilString & rStrKeyWkDir( m_rLLDBDebugSessionInfo.m_constStrSharedDataKeyWkDir );
+ CMIUtilString strWkDir;
+ const bool bOk = m_rLLDBDebugSessionInfo.SharedDataRetrieve< CMIUtilString >( rStrKeyWkDir, strWkDir );
+ if( bOk )
+ {
+ const CMICmnMIValueConst miValueConst( strWkDir );
+ const CMICmnMIValueResult miValueResult( "path", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_SHARED_DATA_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), rStrKeyWkDir.c_str() ) );
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdEnvironmentCd::CreateSelf( void )
+{
+ return new CMICmdCmdEnvironmentCd();
+}
diff --git a/tools/lldb-mi/MICmdCmdEnviro.h b/tools/lldb-mi/MICmdCmdEnviro.h
new file mode 100644
index 000000000000..efbe89238218
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdEnviro.h
@@ -0,0 +1,69 @@
+//===-- MICmdCmdEnviro.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdEnviro.h
+//
+// Overview: CMICmdCmdEnvironmentCd interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdBase.h"
+#include "MICmnMIValueTuple.h"
+#include "MICmnMIValueList.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "environment-cd".
+// Gotchas: None.
+// Authors: Illya Rudkin 03/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdEnvironmentCd : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdEnvironmentCd( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdEnvironmentCd( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgNamePathDir;
+};
+
diff --git a/tools/lldb-mi/MICmdCmdExec.cpp b/tools/lldb-mi/MICmdCmdExec.cpp
new file mode 100644
index 000000000000..c0ec25d701b7
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdExec.cpp
@@ -0,0 +1,982 @@
+//===-- MICmdCmdExec.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdExec.cpp
+//
+// Overview: CMICmdCmdExecRun implementation.
+// CMICmdCmdExecContinue implementation.
+// CMICmdCmdExecNext implementation.
+// CMICmdCmdExecStep implementation.
+// CMICmdCmdExecNextInstruction implementation.
+// CMICmdCmdExecStepInstruction implementation.
+// CMICmdCmdExecFinish implementation.
+// CMICmdCmdExecInterrupt implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third Party Headers:
+#include <lldb/API/SBCommandInterpreter.h>
+#include <lldb/API/SBProcess.h>
+#include <lldb/API/SBStream.h>
+#include "lldb/lldb-enumerations.h"
+
+// In-house headers:
+#include "MICmdCmdExec.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnLLDBDebugger.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MIDriver.h"
+#include "MICmdArgValNumber.h"
+#include "MICmdArgValString.h"
+#include "MICmdArgValThreadGrp.h"
+#include "MICmdArgValOptionLong.h"
+#include "MICmdArgValOptionShort.h"
+#include "MICmdArgValListOfN.h"
+#include "MICmnStreamStdout.h"
+#include "MICmnMIOutOfBandRecord.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecRun constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecRun::CMICmdCmdExecRun( void )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "exec-run";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdExecRun::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecRun destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecRun::~CMICmdCmdExecRun( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecRun::Execute( void )
+{
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBError error;
+ lldb::SBStream errMsg;
+ uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug;
+ lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch (rSessionInfo.m_rLlldbListener,
+ nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, launch_flags, false, error);
+
+ if( (!process.IsValid()) || (error.Fail()) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_PROCESS ), m_cmdData.strMiCmd.c_str(), errMsg.GetData() ) );
+ return MIstatus::failure;
+ }
+
+ // Save the process in the session info
+ rSessionInfo.m_lldbProcess = process;
+
+ if( !CMIDriver::Instance().SetDriverStateRunningDebugging() )
+ {
+ const CMIUtilString & rErrMsg( CMIDriver::Instance().GetErrorDescription() );
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_SET_NEW_DRIVER_STATE ), m_cmdData.strMiCmd.c_str(), rErrMsg.c_str() ) );
+ return MIstatus::failure;
+ }
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecRun::Acknowledge( void )
+{
+ if( m_lldbResult.GetErrorSize() > 0 )
+ {
+ const CMICmnMIValueConst miValueConst( m_lldbResult.GetError() );
+ const CMICmnMIValueResult miValueResult( "message", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ }
+ else
+ {
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Running );
+ m_miResultRecord = miRecordResult;
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID();
+ // Give the client '=thread-group-started,id="i1" pid="xyz"'
+ m_bHasResultRecordExtra = true;
+ const CMICmnMIValueConst miValueConst2( "i1" );
+ const CMICmnMIValueResult miValueResult2( "id", miValueConst2 );
+ const CMIUtilString strPid( CMIUtilString::Format( "%lld", pid ) );
+ const CMICmnMIValueConst miValueConst( strPid );
+ const CMICmnMIValueResult miValueResult( "pid", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBand( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, miValueResult2 );
+ miOutOfBand.Add( miValueResult );
+ m_miResultRecordExtra = miOutOfBand.GetString();
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdExecRun::CreateSelf( void )
+{
+ return new CMICmdCmdExecRun();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecContinue constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecContinue::CMICmdCmdExecContinue( void )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "exec-continue";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdExecContinue::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecContinue destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecContinue::~CMICmdCmdExecContinue( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecContinue::Execute( void )
+{
+ const MIchar * pCmd = "continue";
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ const lldb::ReturnStatus rtn = rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand( pCmd, m_lldbResult ); MIunused( rtn );
+
+
+ if( m_lldbResult.GetErrorSize() == 0 )
+ {
+ // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
+ if( !CMIDriver::Instance().SetDriverStateRunningDebugging() )
+ {
+ const CMIUtilString & rErrMsg( CMIDriver::Instance().GetErrorDescription() );
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_SET_NEW_DRIVER_STATE ), m_cmdData.strMiCmd.c_str(), rErrMsg.c_str() ) );
+ return MIstatus::failure;
+ }
+ }
+ else
+ {
+ // ToDo: Re-evaluate if this is required when application near finished as this is parsing LLDB error message
+ // which seems a hack and is code brittle
+ const MIchar * pLldbErr = m_lldbResult.GetError();
+ const CMIUtilString strLldbMsg( CMIUtilString( pLldbErr ).StripCREndOfLine() );
+ if( strLldbMsg == "error: Process must be launched." )
+ {
+ CMIDriver::Instance().SetExitApplicationFlag( true );
+ }
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecContinue::Acknowledge( void )
+{
+ if( m_lldbResult.GetErrorSize() > 0 )
+ {
+ const CMICmnMIValueConst miValueConst( m_lldbResult.GetError() );
+ const CMICmnMIValueResult miValueResult( "message", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ }
+ else
+ {
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Running );
+ m_miResultRecord = miRecordResult;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdExecContinue::CreateSelf( void )
+{
+ return new CMICmdCmdExecContinue();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecNext constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecNext::CMICmdCmdExecNext( void )
+: m_constStrArgThread( "thread" )
+, m_constStrArgNumber( "number" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "exec-next";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdExecNext::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecNext destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecNext::~CMICmdCmdExecNext( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecNext::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgNumber, false, false ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecNext::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
+
+ // Retrieve the --thread option's thread ID (only 1)
+ MIuint64 nThreadId = UINT64_MAX;
+ if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_THREAD_INVALID ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBDebugger & rDebugger = rSessionInfo.m_rLldbDebugger;
+ CMIUtilString strCmd( "thread step-over" );
+ if( nThreadId != UINT64_MAX )
+ strCmd += CMIUtilString::Format( " %llu", nThreadId );
+ rDebugger.GetCommandInterpreter().HandleCommand( strCmd.c_str(), m_lldbResult, false );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecNext::Acknowledge( void )
+{
+ if( m_lldbResult.GetErrorSize() > 0 )
+ {
+ const MIchar * pLldbErr = m_lldbResult.GetError(); MIunused( pLldbErr );
+ const CMICmnMIValueConst miValueConst( m_lldbResult.GetError() );
+ const CMICmnMIValueResult miValueResult( "message", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ }
+ else
+ {
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Running );
+ m_miResultRecord = miRecordResult;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdExecNext::CreateSelf( void )
+{
+ return new CMICmdCmdExecNext();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecStep constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecStep::CMICmdCmdExecStep( void )
+: m_constStrArgThread( "thread" )
+, m_constStrArgNumber( "number" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "exec-step";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdExecStep::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecStep destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecStep::~CMICmdCmdExecStep( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecStep::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgNumber, false, false ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecStep::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
+
+ // Retrieve the --thread option's thread ID (only 1)
+ MIuint64 nThreadId = UINT64_MAX;
+ if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBDebugger & rDebugger = rSessionInfo.m_rLldbDebugger;
+ CMIUtilString strCmd( "thread step-in" );
+ if( nThreadId != UINT64_MAX )
+ strCmd += CMIUtilString::Format( " %llu", nThreadId );
+ rDebugger.GetCommandInterpreter().HandleCommand( strCmd.c_str(), m_lldbResult, false );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecStep::Acknowledge( void )
+{
+ if( m_lldbResult.GetErrorSize() > 0 )
+ {
+ const MIchar * pLldbErr = m_lldbResult.GetError(); MIunused( pLldbErr );
+ const CMICmnMIValueConst miValueConst( m_lldbResult.GetError() );
+ const CMICmnMIValueResult miValueResult( "message", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ }
+ else
+ {
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Running );
+ m_miResultRecord = miRecordResult;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdExecStep::CreateSelf( void )
+{
+ return new CMICmdCmdExecStep();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecNextInstruction constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecNextInstruction::CMICmdCmdExecNextInstruction( void )
+: m_constStrArgThread( "thread" )
+, m_constStrArgNumber( "number" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "exec-next-instruction";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdExecNextInstruction::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecNextInstruction destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecNextInstruction::~CMICmdCmdExecNextInstruction( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecNextInstruction::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgNumber, false, false ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecNextInstruction::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
+
+ // Retrieve the --thread option's thread ID (only 1)
+ MIuint64 nThreadId = UINT64_MAX;
+ if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBDebugger & rDebugger = rSessionInfo.m_rLldbDebugger;
+ CMIUtilString strCmd( "thread step-inst-over" );
+ if( nThreadId != UINT64_MAX )
+ strCmd += CMIUtilString::Format( " %llu", nThreadId );
+ rDebugger.GetCommandInterpreter().HandleCommand( strCmd.c_str(), m_lldbResult, false );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecNextInstruction::Acknowledge( void )
+{
+ if( m_lldbResult.GetErrorSize() > 0 )
+ {
+ const MIchar * pLldbErr = m_lldbResult.GetError(); MIunused( pLldbErr );
+ const CMICmnMIValueConst miValueConst( m_lldbResult.GetError() );
+ const CMICmnMIValueResult miValueResult( "message", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ }
+ else
+ {
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Running );
+ m_miResultRecord = miRecordResult;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdExecNextInstruction::CreateSelf( void )
+{
+ return new CMICmdCmdExecNextInstruction();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecStepInstruction constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecStepInstruction::CMICmdCmdExecStepInstruction( void )
+: m_constStrArgThread( "thread" )
+, m_constStrArgNumber( "number" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "exec-step-instruction";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdExecStepInstruction::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecStepInstruction destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecStepInstruction::~CMICmdCmdExecStepInstruction( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecStepInstruction::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgNumber, false, false ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecStepInstruction::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
+
+ // Retrieve the --thread option's thread ID (only 1)
+ MIuint64 nThreadId = UINT64_MAX;
+ if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBDebugger & rDebugger = rSessionInfo.m_rLldbDebugger;
+ CMIUtilString strCmd( "thread step-inst" );
+ if( nThreadId != UINT64_MAX )
+ strCmd += CMIUtilString::Format( " %llu", nThreadId );
+ rDebugger.GetCommandInterpreter().HandleCommand( strCmd.c_str(), m_lldbResult, false );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecStepInstruction::Acknowledge( void )
+{
+ if( m_lldbResult.GetErrorSize() > 0 )
+ {
+ const MIchar * pLldbErr = m_lldbResult.GetError(); MIunused( pLldbErr );
+ const CMICmnMIValueConst miValueConst( m_lldbResult.GetError() );
+ const CMICmnMIValueResult miValueResult( "message", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ }
+ else
+ {
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Running );
+ m_miResultRecord = miRecordResult;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdExecStepInstruction::CreateSelf( void )
+{
+ return new CMICmdCmdExecStepInstruction();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecFinish constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecFinish::CMICmdCmdExecFinish( void )
+: m_constStrArgThread( "thread" )
+, m_constStrArgFrame( "frame" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "exec-finish";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdExecFinish::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecFinish destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecFinish::~CMICmdCmdExecFinish( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecFinish::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgFrame, false, false, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecFinish::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
+
+ // Retrieve the --thread option's thread ID (only 1)
+ MIuint64 nThreadId = UINT64_MAX;
+ if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBDebugger & rDebugger = rSessionInfo.m_rLldbDebugger;
+ CMIUtilString strCmd( "thread step-out" );
+ if( nThreadId != UINT64_MAX )
+ strCmd += CMIUtilString::Format( " %llu", nThreadId );
+ rDebugger.GetCommandInterpreter().HandleCommand( strCmd.c_str(), m_lldbResult, false );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecFinish::Acknowledge( void )
+{
+ if( m_lldbResult.GetErrorSize() > 0 )
+ {
+ const MIchar * pLldbErr = m_lldbResult.GetError(); MIunused( pLldbErr );
+ const CMICmnMIValueConst miValueConst( m_lldbResult.GetError() );
+ const CMICmnMIValueResult miValueResult( "message", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ }
+ else
+ {
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Running );
+ m_miResultRecord = miRecordResult;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdExecFinish::CreateSelf( void )
+{
+ return new CMICmdCmdExecFinish();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecInterrupt constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecInterrupt::CMICmdCmdExecInterrupt( void )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "exec-interrupt";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdExecInterrupt::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdExecInterrupt destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdExecInterrupt::~CMICmdCmdExecInterrupt( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecInterrupt::Execute( void )
+{
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBDebugger & rDebugger = rSessionInfo.m_rLldbDebugger;
+ CMIUtilString strCmd( "process interrupt" );
+ const lldb::ReturnStatus status = rDebugger.GetCommandInterpreter().HandleCommand( strCmd.c_str(), m_lldbResult, false ); MIunused( status );
+
+ // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
+ if( !CMIDriver::Instance().SetDriverStateRunningNotDebugging() )
+ {
+ const CMIUtilString & rErrMsg( CMIDriver::Instance().GetErrorDescription() );
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_SET_NEW_DRIVER_STATE ), strCmd.c_str(), rErrMsg.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdExecInterrupt::Acknowledge( void )
+{
+ if( m_lldbResult.GetErrorSize() > 0 )
+ {
+ const CMICmnMIValueConst miValueConst( m_lldbResult.GetError() );
+ const CMICmnMIValueResult miValueResult( "message", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ }
+ else
+ {
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdExecInterrupt::CreateSelf( void )
+{
+ return new CMICmdCmdExecInterrupt();
+}
+
diff --git a/tools/lldb-mi/MICmdCmdExec.h b/tools/lldb-mi/MICmdCmdExec.h
new file mode 100644
index 000000000000..a712b23ca5e0
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdExec.h
@@ -0,0 +1,310 @@
+//===-- MICmdCmdExec.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdExec.h
+//
+// Overview: CMICmdCmdExecRun interface.
+// CMICmdCmdExecContinue interface.
+// CMICmdCmdExecNext interface.
+// CMICmdCmdExecStep interface.
+// CMICmdCmdExecNextInstruction interface.
+// CMICmdCmdExecStepInstruction interface.
+// CMICmdCmdExecFinish interface.
+// CMICmdCmdExecInterrupt interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <lldb/API/SBCommandReturnObject.h>
+
+// In-house headers:
+#include "MICmdBase.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "exec-run".
+// Gotchas: None.
+// Authors: Illya Rudkin 07/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdExecRun : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdExecRun( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdExecRun( void );
+
+// Attributes:
+private:
+ lldb::SBCommandReturnObject m_lldbResult;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "exec-continue".
+// Gotchas: None.
+// Authors: Illya Rudkin 07/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdExecContinue : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdExecContinue( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdExecContinue( void );
+
+// Attributes:
+private:
+ lldb::SBCommandReturnObject m_lldbResult;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "exec-next".
+// Gotchas: None.
+// Authors: Illya Rudkin 25/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdExecNext : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdExecNext( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdExecNext( void );
+
+// Attributes:
+private:
+ lldb::SBCommandReturnObject m_lldbResult;
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgNumber; // Not specified in MI spec but Eclipse gives this option
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "exec-step".
+// Gotchas: None.
+// Authors: Illya Rudkin 25/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdExecStep : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdExecStep( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdExecStep( void );
+
+// Attributes:
+private:
+ lldb::SBCommandReturnObject m_lldbResult;
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgNumber; // Not specified in MI spec but Eclipse gives this option
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "exec-next-instruction".
+// Gotchas: None.
+// Authors: Illya Rudkin 25/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdExecNextInstruction : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdExecNextInstruction( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdExecNextInstruction( void );
+
+// Attributes:
+private:
+ lldb::SBCommandReturnObject m_lldbResult;
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgNumber; // Not specified in MI spec but Eclipse gives this option
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "exec-step-instruction".
+// Gotchas: None.
+// Authors: Illya Rudkin 25/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdExecStepInstruction : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdExecStepInstruction( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdExecStepInstruction( void );
+
+// Attributes:
+private:
+ lldb::SBCommandReturnObject m_lldbResult;
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgNumber; // Not specified in MI spec but Eclipse gives this option
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "exec-finish".
+// Gotchas: None.
+// Authors: Illya Rudkin 25/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdExecFinish : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdExecFinish( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdExecFinish( void );
+
+// Attributes:
+private:
+ lldb::SBCommandReturnObject m_lldbResult;
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgFrame; // Not specified in MI spec but Eclipse gives this option
+};
+
+// CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "exec-interrupt".
+// Gotchas: Using Eclipse this command is injected into the command system when a
+// SIGINT signal is received while running an inferior program.
+// Authors: Illya Rudkin 03/06/2014.
+// Changes: None.
+//--
+class CMICmdCmdExecInterrupt : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdExecInterrupt( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdExecInterrupt( void );
+
+// Attributes:
+private:
+ lldb::SBCommandReturnObject m_lldbResult;
+};
+
diff --git a/tools/lldb-mi/MICmdCmdFile.cpp b/tools/lldb-mi/MICmdCmdFile.cpp
new file mode 100644
index 000000000000..1d0b494362ce
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdFile.cpp
@@ -0,0 +1,184 @@
+//===-- MICmdCmdFile.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdFile.cpp
+//
+// Overview: CMICmdCmdFileExecAndSymbols implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third Party Headers:
+#include <lldb/API/SBStream.h>
+
+// In-house headers:
+#include "MICmdCmdFile.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnLLDBDebugger.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MIUtilFileStd.h"
+#include "MICmdArgValFile.h"
+#include "MICmdArgValOptionLong.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdFileExecAndSymbols constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdFileExecAndSymbols::CMICmdCmdFileExecAndSymbols( void )
+: m_constStrArgNameFile( "file" )
+, m_constStrArgThreadGrp( "thread-group" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "file-exec-and-symbols";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdFileExecAndSymbols::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdFileExecAndSymbols destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdFileExecAndSymbols::~CMICmdCmdFileExecAndSymbols( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdFileExecAndSymbols::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThreadGrp, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValFile( m_constStrArgNameFile, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Synopsis: -file-exec-and-symbols file
+// Ref: http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-File-Commands.html#GDB_002fMI-File-Commands
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdFileExecAndSymbols::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgNamedFile, File, m_constStrArgNameFile );
+ CMICmdArgValFile * pArgFile = static_cast< CMICmdArgValFile * >( pArgNamedFile );
+ const CMIUtilString & strExeFilePath( pArgFile->GetValue() );
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBDebugger & rDbgr = rSessionInfo.m_rLldbDebugger;
+ lldb::SBError error;
+ const MIchar * pTargetTriple = nullptr; // Let LLDB discover the triple required
+ const MIchar * pTargetPlatformName = "";
+ const bool bAddDepModules = false;
+ lldb::SBTarget target = rDbgr.CreateTarget( strExeFilePath.c_str(), pTargetTriple, pTargetPlatformName, bAddDepModules, error );
+ CMIUtilString strWkDir;
+ const CMIUtilString & rStrKeyWkDir( rSessionInfo.m_constStrSharedDataKeyWkDir );
+ if( !rSessionInfo.SharedDataRetrieve< CMIUtilString >( rStrKeyWkDir, strWkDir ) )
+ {
+ strWkDir = CMIUtilFileStd().StripOffFileName( strExeFilePath );
+ if( !rSessionInfo.SharedDataAdd< CMIUtilString >( rStrKeyWkDir, strWkDir ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_DBGSESSION_ERR_SHARED_DATA_ADD ), m_cmdData.strMiCmd.c_str(), rStrKeyWkDir.c_str() ) );
+ return MIstatus::failure;
+ }
+ }
+ if( !rDbgr.SetCurrentPlatformSDKRoot( strWkDir.c_str() ) )
+ {
+
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_FNFAILED ), m_cmdData.strMiCmd.c_str(), "SetCurrentPlatformSDKRoot()" ) );
+ return MIstatus::failure;
+ }
+ lldb::SBStream err;
+ if( error.Fail() )
+ {
+ const bool bOk = error.GetDescription( err ); MIunused( bOk );
+ }
+ if( !target.IsValid() )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_TARGET ), m_cmdData.strMiCmd.c_str(), strExeFilePath.c_str(), err.GetData() ) );
+ return MIstatus::failure;
+ }
+ if( error.Fail() )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_CREATE_TARGET ), m_cmdData.strMiCmd.c_str(), err.GetData() ) );
+ return MIstatus::failure;
+ }
+
+ rSessionInfo.m_lldbTarget = target;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdFileExecAndSymbols::Acknowledge( void )
+{
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdFileExecAndSymbols::CreateSelf( void )
+{
+ return new CMICmdCmdFileExecAndSymbols();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: If the MI Driver is not operating via a client i.e. Eclipse but say operating
+// on a executable passed in as a argument to the drive then what should the driver
+// do on a command failing? Either continue operating or exit the application.
+// Override this function where a command failure cannot allow the driver to
+// continue operating.
+// Type: Overridden.
+// Args: None.
+// Return: bool - True = Fatal if command fails, false = can continue if command fails.
+// Throws: None.
+//--
+bool CMICmdCmdFileExecAndSymbols::GetExitAppOnCommandFailure( void ) const
+{
+ return true;
+} \ No newline at end of file
diff --git a/tools/lldb-mi/MICmdCmdFile.h b/tools/lldb-mi/MICmdCmdFile.h
new file mode 100644
index 000000000000..a80a313ea7b5
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdFile.h
@@ -0,0 +1,71 @@
+//===-- MICmdCmdFile.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdFile.h
+//
+// Overview: CMICmdCmdFileExecAndSymbols interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdBase.h"
+#include "MICmnMIValueTuple.h"
+#include "MICmnMIValueList.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "file-exec-and-symbols".
+// This command does not follow the MI documentation exactly.
+// Gotchas: None.
+// Authors: Illya Rudkin 25/02/2014.
+// Changes: None.
+//--
+class CMICmdCmdFileExecAndSymbols : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdFileExecAndSymbols( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdFileExecAndSymbols( void );
+ virtual bool GetExitAppOnCommandFailure( void ) const;
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgNameFile;
+ const CMIUtilString m_constStrArgThreadGrp; // Not handled by *this command. Not specified in MI spec but Eclipse gives this option sometimes
+};
diff --git a/tools/lldb-mi/MICmdCmdGdbInfo.cpp b/tools/lldb-mi/MICmdCmdGdbInfo.cpp
new file mode 100644
index 000000000000..62bb1f280bc3
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdGdbInfo.cpp
@@ -0,0 +1,232 @@
+//===-- MICmdCmdGdbInfo.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdGdbInfo.cpp
+//
+// Overview: CMICmdCmdGdbInfo implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third party headers:
+#include <lldb/API/SBCommandReturnObject.h>
+
+// In-house headers:
+#include "MICmdCmdGdbInfo.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmdArgValString.h"
+#include "MICmnStreamStdout.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+
+// Instantiations:
+const CMICmdCmdGdbInfo::MapPrintFnNameToPrintFn_t CMICmdCmdGdbInfo::ms_mapPrintFnNameToPrintFn =
+{
+ { "sharedlibrary", &CMICmdCmdGdbInfo::PrintFnSharedLibrary }
+};
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdGdbInfo constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdGdbInfo::CMICmdCmdGdbInfo( void )
+: m_constStrArgNamedPrint( "print" )
+, m_bPrintFnRecognised( true )
+, m_bPrintFnSuccessful( false )
+, m_strPrintFnError( MIRSRC( IDS_WORD_ERR_MSG_NOT_IMPLEMENTED_BRKTS ) )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "info";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdGdbInfo::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdGdbInfo destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdGdbInfo::~CMICmdCmdGdbInfo( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbInfo::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgNamedPrint, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbInfo::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgPrint, String, m_constStrArgNamedPrint );
+ const CMIUtilString & rPrintRequest( pArgPrint->GetValue() );
+
+ FnPrintPtr pPrintRequestFn = nullptr;
+ if( !GetPrintFn( rPrintRequest, pPrintRequestFn ) )
+ {
+ m_strPrintFnName = rPrintRequest;
+ m_bPrintFnRecognised = false;
+ return MIstatus::success;
+ }
+
+ m_bPrintFnSuccessful = (this->*(pPrintRequestFn))();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbInfo::Acknowledge( void )
+{
+ if( !m_bPrintFnRecognised )
+ {
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND ), m_strPrintFnName.c_str() ) );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ if( m_bPrintFnSuccessful )
+ {
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INFO_PRINTFN_FAILED ), m_strPrintFnError.c_str() ) );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdGdbInfo::CreateSelf( void )
+{
+ return new CMICmdCmdGdbInfo();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the print function's pointer for the matching print request.
+// Type: Method.
+// Args: vrPrintFnName - (R) The info requested.
+// vrwpFn - (W) The print function's pointer of the function to carry out
+// Return: bool - True = Print request is implemented, false = not found.
+// Throws: None.
+//--
+bool CMICmdCmdGdbInfo::GetPrintFn( const CMIUtilString & vrPrintFnName, FnPrintPtr & vrwpFn ) const
+{
+ vrwpFn = nullptr;
+
+ const MapPrintFnNameToPrintFn_t::const_iterator it = ms_mapPrintFnNameToPrintFn.find( vrPrintFnName );
+ if( it != ms_mapPrintFnNameToPrintFn.end() )
+ {
+ vrwpFn = (*it).second;
+ return true;
+ }
+
+ return false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Carry out work to complete the request to prepare and send back information
+// asked for.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbInfo::PrintFnSharedLibrary( void )
+{
+ CMICmnStreamStdout & rStdout = CMICmnStreamStdout::Instance();
+ bool bOk = rStdout.TextToStdout( "~\"From To Syms Read Shared Object Library\"" );
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBTarget & rTarget = rSessionInfo.m_lldbTarget;
+ const MIuint nModules = rTarget.GetNumModules();
+ for( MIuint i = 0; bOk && (i < nModules); i++ )
+ {
+ lldb::SBModule module = rTarget.GetModuleAtIndex( i );
+ if( module.IsValid() )
+ {
+ const CMIUtilString strModuleFilePath( module.GetFileSpec().GetDirectory() );
+ const CMIUtilString strModuleFileName( module.GetFileSpec().GetFilename() );
+ const CMIUtilString strModuleFullPath( CMIUtilString::Format( "%s/%s", strModuleFilePath.c_str(), strModuleFileName.c_str() ) );
+ const CMIUtilString strHasSymbols = (module.GetNumSymbols() > 0) ? "Yes" : "No";
+ lldb::addr_t addrLoadS = 0xffffffff;
+ lldb::addr_t addrLoadSize = 0;
+ bool bHaveAddrLoad = false;
+ const MIuint nSections = module.GetNumSections();
+ for( MIuint j = 0; j < nSections; j++ )
+ {
+ lldb::SBSection section = module.GetSectionAtIndex( j );
+ lldb::addr_t addrLoad = section.GetLoadAddress( rTarget );
+ if( addrLoad != (lldb::addr_t) -1 )
+ {
+ if( !bHaveAddrLoad )
+ {
+ bHaveAddrLoad = true;
+ addrLoadS = addrLoad;
+ }
+
+ addrLoadSize += section.GetByteSize();
+ }
+ }
+ bOk = bOk && rStdout.TextToStdout( CMIUtilString::Format( "~\"0x%08x\t0x%08x\t%s\t\t%s\"", addrLoadS, addrLoadS + addrLoadSize, strHasSymbols.c_str(), strModuleFullPath.c_str() ) );
+ }
+ }
+
+ return bOk;
+}
diff --git a/tools/lldb-mi/MICmdCmdGdbInfo.h b/tools/lldb-mi/MICmdCmdGdbInfo.h
new file mode 100644
index 000000000000..3fa920669416
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdGdbInfo.h
@@ -0,0 +1,93 @@
+//===-- MICmdCmdGdbInfo.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdGdbInfo.h
+//
+// Overview: CMICmdCmdGdbInfo interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <map>
+
+// In-house headers:
+#include "MICmdBase.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements GDB command "info".
+// The design of matching the info request to a request action (or
+// command) is very simple. The request function which carries out
+// the task of information gathering and printing to stdout is part of
+// *this class. Should the request function become more complicated then
+// that request should really reside in a command type class. Then this
+// class instantiates a request info command for a matching request. The
+// design/code of *this class then does not then become bloated. Use a
+// lightweight version of the current MI command system.
+// Gotchas: None.
+// Authors: Illya Rudkin 05/06/2014.
+// Changes: None.
+//--
+class CMICmdCmdGdbInfo : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdGdbInfo( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdGdbInfo( void );
+
+// Typedefs:
+private:
+ typedef bool (CMICmdCmdGdbInfo::*FnPrintPtr)();
+ typedef std::map< CMIUtilString, FnPrintPtr > MapPrintFnNameToPrintFn_t;
+
+// Methods:
+private:
+ bool GetPrintFn( const CMIUtilString & vrPrintFnName, FnPrintPtr & vrwpFn ) const;
+ bool PrintFnSharedLibrary( void );
+
+// Attributes:
+private:
+ const static MapPrintFnNameToPrintFn_t ms_mapPrintFnNameToPrintFn;
+ //
+ const CMIUtilString m_constStrArgNamedPrint;
+ bool m_bPrintFnRecognised; // True = This command has a function with a name that matches the Print argument, false = not found
+ bool m_bPrintFnSuccessful; // True = The print function completed its task ok, false = function failed for some reason
+ CMIUtilString m_strPrintFnName;
+ CMIUtilString m_strPrintFnError;
+}; \ No newline at end of file
diff --git a/tools/lldb-mi/MICmdCmdGdbSet.cpp b/tools/lldb-mi/MICmdCmdGdbSet.cpp
new file mode 100644
index 000000000000..a256ee2e2ca1
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdGdbSet.cpp
@@ -0,0 +1,260 @@
+//===-- MICmdCmdGdbSet.cpp ------- -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdGdbSet.cpp
+//
+// Overview: CMICmdCmdGdbSet implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdCmdGdbSet.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmdArgValString.h"
+#include "MICmdArgValListOfN.h"
+#include "MICmdArgValOptionLong.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+
+// Instantiations:
+const CMICmdCmdGdbSet::MapGdbOptionNameToFnGdbOptionPtr_t CMICmdCmdGdbSet::ms_mapGdbOptionNameToFnGdbOptionPtr =
+{
+ // { "target-async", &CMICmdCmdGdbSet::OptionFnTargetAsync }, // Example code if need to implement GDB set other options
+ // { "auto-solib-add", &CMICmdCmdGdbSet::OptionFnAutoSolibAdd }, // Example code if need to implement GDB set other options
+ { "solib-search-path", &CMICmdCmdGdbSet::OptionFnSolibSearchPath },
+ { "fallback", &CMICmdCmdGdbSet::OptionFnFallback }
+};
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdGdbSet constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdGdbSet::CMICmdCmdGdbSet( void )
+: m_constStrArgNamedThreadGrp( "thread-group" )
+, m_constStrArgNamedGdbOption( "option" )
+, m_bGdbOptionRecognised( true )
+, m_bGdbOptionFnSuccessful( false )
+, m_bGbbOptionFnHasError( false )
+, m_strGdbOptionFnError( MIRSRC( IDS_WORD_ERR_MSG_NOT_IMPLEMENTED_BRKTS ) )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "gdb-set";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdGdbSet::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdGdbSet destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdGdbSet::~CMICmdCmdGdbSet( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbSet::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgNamedThreadGrp, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValListOfN( m_constStrArgNamedGdbOption, true, true, CMICmdArgValListBase::eArgValType_StringAnything ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbSet::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgGdbOption, ListOfN, m_constStrArgNamedGdbOption );
+ const CMICmdArgValListBase::VecArgObjPtr_t & rVecWords( pArgGdbOption->GetExpectedOptions() );
+
+ // Get the gdb-set option to carry out
+ CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecWords.begin();
+ const CMICmdArgValString * pOption = static_cast< const CMICmdArgValString * >( *it );
+ const CMIUtilString strOption( pOption->GetValue() );
+ ++it;
+
+ // Retrieve the parameter(s) for the option
+ CMIUtilString::VecString_t vecWords;
+ while( it != rVecWords.end() )
+ {
+ const CMICmdArgValString * pWord = static_cast< const CMICmdArgValString * >( *it );
+ vecWords.push_back( pWord->GetValue() );
+
+ // Next
+ ++it;
+ }
+
+ FnGdbOptionPtr pPrintRequestFn = nullptr;
+ if( !GetOptionFn( strOption, pPrintRequestFn ) )
+ {
+ // For unimplemented option handlers, fallback on a generic handler
+ // ToDo: Remove this when ALL options have been implemented
+ if( !GetOptionFn( "fallback", pPrintRequestFn ) )
+ {
+ m_bGdbOptionRecognised = false;
+ m_strGdbOptionName = "fallback"; // This would be the strOption name
+ return MIstatus::success;
+ }
+ }
+
+ m_bGdbOptionFnSuccessful = (this->*(pPrintRequestFn))( vecWords );
+ if( !m_bGdbOptionFnSuccessful && !m_bGbbOptionFnHasError )
+ return MIstatus::failure;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbSet::Acknowledge( void )
+{
+ if( !m_bGdbOptionRecognised )
+ {
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND ), m_strGdbOptionName.c_str() ) );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ if( m_bGdbOptionFnSuccessful )
+ {
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INFO_PRINTFN_FAILED ), m_strGdbOptionFnError.c_str() ) );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdGdbSet::CreateSelf( void )
+{
+ return new CMICmdCmdGdbSet();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the print function's pointer for the matching print request.
+// Type: Method.
+// Args: vrPrintFnName - (R) The info requested.
+// vrwpFn - (W) The print function's pointer of the function to carry out
+// Return: bool - True = Print request is implemented, false = not found.
+// Throws: None.
+//--
+bool CMICmdCmdGdbSet::GetOptionFn( const CMIUtilString & vrPrintFnName, FnGdbOptionPtr & vrwpFn ) const
+{
+ vrwpFn = nullptr;
+
+ const MapGdbOptionNameToFnGdbOptionPtr_t::const_iterator it = ms_mapGdbOptionNameToFnGdbOptionPtr.find( vrPrintFnName );
+ if( it != ms_mapGdbOptionNameToFnGdbOptionPtr.end() )
+ {
+ vrwpFn = (*it).second;
+ return true;
+ }
+
+ return false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Carry out work to complete the GDB set option 'solib-search-path' to prepare
+// and send back information asked for.
+// Type: Method.
+// Args: vrWords - (R) List of additional parameters used by this option.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbSet::OptionFnSolibSearchPath( const CMIUtilString::VecString_t & vrWords )
+{
+ // Check we have at least one argument
+ if( vrWords.size() < 1 )
+ {
+ m_bGbbOptionFnHasError = true;
+ m_strGdbOptionFnError = MIRSRC( IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH );
+ return MIstatus::failure;
+ }
+ const CMIUtilString & rStrValSolibPath( vrWords[ 0 ] );
+
+ // Add 'solib-search-path' to the shared data list
+ const CMIUtilString & rStrKeySolibPath( m_rLLDBDebugSessionInfo.m_constStrSharedDataSolibPath );
+ if( !m_rLLDBDebugSessionInfo.SharedDataAdd< CMIUtilString >( rStrKeySolibPath, rStrValSolibPath ) )
+ {
+ m_bGbbOptionFnHasError = false;
+ SetError( CMIUtilString::Format( MIRSRC( IDS_DBGSESSION_ERR_SHARED_DATA_ADD ), m_cmdData.strMiCmd.c_str(), rStrKeySolibPath.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Carry out work to complete the GDB set option to prepare and send back information
+// asked for.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbSet::OptionFnFallback( const CMIUtilString::VecString_t & vrWords )
+{
+ MIunused( vrWords );
+
+ // Do nothing - intentional. This is a fallback temporary action function to do nothing.
+ // This allows the search for gdb-set options to always suceed when the option is not
+ // found (implemented).
+
+ return MIstatus::success;
+}
diff --git a/tools/lldb-mi/MICmdCmdGdbSet.h b/tools/lldb-mi/MICmdCmdGdbSet.h
new file mode 100644
index 000000000000..24b54557bf37
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdGdbSet.h
@@ -0,0 +1,96 @@
+//===-- MICmdCmdGdbSet.h ------------- ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdGdbSet.h
+//
+// Overview: CMICmdCmdGdbSet interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdBase.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "gdb-set".
+// This command does not follow the MI documentation exactly. While *this
+// command is implemented it does not do anything with the gdb-set
+// variable past in.
+// The design of matching the info request to a request action (or
+// command) is very simple. The request function which carries out
+// the task of information gathering and printing to stdout is part of
+// *this class. Should the request function become more complicated then
+// that request should really reside in a command type class. Then this
+// class instantiates a request info command for a matching request. The
+// design/code of *this class then does not then become bloated. Use a
+// lightweight version of the current MI command system.
+// Gotchas: None.
+// Authors: Illya Rudkin 03/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdGdbSet : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdGdbSet( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdGdbSet( void );
+
+// Typedefs:
+private:
+ typedef bool (CMICmdCmdGdbSet::*FnGdbOptionPtr)( const CMIUtilString::VecString_t & vrWords );
+ typedef std::map< CMIUtilString, FnGdbOptionPtr > MapGdbOptionNameToFnGdbOptionPtr_t;
+
+// Methods:
+private:
+ bool GetOptionFn( const CMIUtilString & vrGdbOptionName, FnGdbOptionPtr & vrwpFn ) const;
+ bool OptionFnSolibSearchPath( const CMIUtilString::VecString_t & vrWords );
+ bool OptionFnFallback( const CMIUtilString::VecString_t & vrWords );
+
+// Attributes:
+private:
+ const static MapGdbOptionNameToFnGdbOptionPtr_t ms_mapGdbOptionNameToFnGdbOptionPtr;
+ //
+ const CMIUtilString m_constStrArgNamedThreadGrp;
+ const CMIUtilString m_constStrArgNamedGdbOption;
+ bool m_bGdbOptionRecognised; // True = This command has a function with a name that matches the Print argument, false = not found
+ bool m_bGdbOptionFnSuccessful; // True = The print function completed its task ok, false = function failed for some reason
+ bool m_bGbbOptionFnHasError; // True = The option function has an error condition (not the command!), false = option function ok.
+ CMIUtilString m_strGdbOptionName;
+ CMIUtilString m_strGdbOptionFnError;
+}; \ No newline at end of file
diff --git a/tools/lldb-mi/MICmdCmdGdbThread.cpp b/tools/lldb-mi/MICmdCmdGdbThread.cpp
new file mode 100644
index 000000000000..09bd053a65e1
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdGdbThread.cpp
@@ -0,0 +1,100 @@
+//===-- MICmdCmdGdbThread.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdGdbThread.cpp
+//
+// Overview: CMICmdCmdGdbThread implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdCmdGdbThread.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdGdbThread constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdGdbThread::CMICmdCmdGdbThread( void )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "thread";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdGdbThread::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdThread destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdGdbThread::~CMICmdCmdGdbThread( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbThread::Execute( void )
+{
+ // Do nothing
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbThread::Acknowledge( void )
+{
+ const CMICmnMIValueConst miValueConst( MIRSRC( IDS_WORD_NOT_IMPLEMENTED ) );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdGdbThread::CreateSelf( void )
+{
+ return new CMICmdCmdGdbThread();
+} \ No newline at end of file
diff --git a/tools/lldb-mi/MICmdCmdGdbThread.h b/tools/lldb-mi/MICmdCmdGdbThread.h
new file mode 100644
index 000000000000..29c1361b4cf4
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdGdbThread.h
@@ -0,0 +1,61 @@
+//===-- MICmdCmdGdbThread.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdGdbThread.h
+//
+// Overview: CMICmdCmdGdbThread interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdBase.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements GDB command "thread".
+// Gotchas: None.
+// Authors: Illya Rudkin 25/02/2014.
+// Changes: None.
+//--
+class CMICmdCmdGdbThread : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdGdbThread( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdGdbThread( void );
+}; \ No newline at end of file
diff --git a/tools/lldb-mi/MICmdCmdMiscellanous.cpp b/tools/lldb-mi/MICmdCmdMiscellanous.cpp
new file mode 100644
index 000000000000..b09f585598a4
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdMiscellanous.cpp
@@ -0,0 +1,588 @@
+//===-- MICmdCmdMiscellanous.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdMiscellanous.cpp
+//
+// Overview: CMICmdCmdGdbExit implementation.
+// CMICmdCmdListThreadGroups implementation.
+// CMICmdCmdInterpreterExec implementation.
+// CMICmdCmdInferiorTtySet implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third Party Headers:
+#include <lldb/API/SBCommandInterpreter.h>
+#include <lldb/API/SBThread.h>
+
+// In-house headers:
+#include "MICmdCmdMiscellanous.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnMIOutOfBandRecord.h"
+#include "MICmnLLDBDebugger.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MIDriverBase.h"
+#include "MICmdArgValFile.h"
+#include "MICmdArgValNumber.h"
+#include "MICmdArgValString.h"
+#include "MICmdArgValThreadGrp.h"
+#include "MICmdArgValOptionLong.h"
+#include "MICmdArgValOptionShort.h"
+#include "MICmdArgValListOfN.h"
+#include "MICmnStreamStdout.h"
+#include "MICmnStreamStderr.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdGdbExit constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdGdbExit::CMICmdCmdGdbExit( void )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "gdb-exit";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdGdbExit::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdGdbExit destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdGdbExit::~CMICmdCmdGdbExit( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbExit::Execute( void )
+{
+ CMICmnLLDBDebugger::Instance().GetDriver().SetExitApplicationFlag( true );
+ const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.m_lldbProcess.Detach();
+ // Do not check for sbErr.Fail() here, m_lldbProcess is likely !IsValid()
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdGdbExit::Acknowledge( void )
+{
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Exit );
+ m_miResultRecord = miRecordResult;
+
+ // Prod the client i.e. Eclipse with out-of-band results to help it 'continue' because it is using LLDB debugger
+ // Give the client '=thread-group-exited,id="i1"'
+ m_bHasResultRecordExtra = true;
+ const CMICmnMIValueConst miValueConst2( "i1" );
+ const CMICmnMIValueResult miValueResult2( "id", miValueConst2 );
+ const CMICmnMIOutOfBandRecord miOutOfBand( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupExited, miValueResult2 );
+ m_miResultRecordExtra = miOutOfBand.GetString();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdGdbExit::CreateSelf( void )
+{
+ return new CMICmdCmdGdbExit();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdListThreadGroups constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdListThreadGroups::CMICmdCmdListThreadGroups( void )
+: m_bIsI1( false )
+, m_bHaveArgOption( false )
+, m_bHaveArgRecurse( false )
+, m_constStrArgNamedAvailable( "available" )
+, m_constStrArgNamedRecurse( "recurse" )
+, m_constStrArgNamedGroup( "group" )
+, m_constStrArgNamedThreadGroup( "i1" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "list-thread-groups";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdListThreadGroups::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdListThreadGroups destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdListThreadGroups::~CMICmdCmdListThreadGroups( void )
+{
+ m_vecMIValueTuple.clear();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdListThreadGroups::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgNamedAvailable, false, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgNamedRecurse, false, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValListOfN( m_constStrArgNamedGroup, false, true, CMICmdArgValListBase::eArgValType_Number ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValThreadGrp( m_constStrArgNamedThreadGroup, false, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Synopis: -list-thread-groups [ --available ] [ --recurse 1 ] [ group ... ]
+// This command does not follow the MI documentation exactly. Has an extra
+// argument "i1" to handle.
+// Ref: http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Miscellaneous-Commands.html#GDB_002fMI-Miscellaneous-Commands
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdListThreadGroups::Execute( void )
+{
+ if( m_setCmdArgs.IsArgContextEmpty() )
+ // No options so "top level thread groups"
+ return MIstatus::success;
+
+ CMICMDBASE_GETOPTION( pArgAvailable, OptionLong, m_constStrArgNamedAvailable );
+ CMICMDBASE_GETOPTION( pArgRecurse, OptionLong, m_constStrArgNamedRecurse );
+ CMICMDBASE_GETOPTION( pArgThreadGroup, ThreadGrp, m_constStrArgNamedThreadGroup );
+
+ // Got some options so "threads"
+ if( pArgAvailable->GetFound() )
+ {
+ if( pArgRecurse->GetFound() )
+ {
+ m_bHaveArgRecurse = true;
+ return MIstatus::success;
+ }
+
+ m_bHaveArgOption = true;
+ return MIstatus::success;
+ }
+ // "i1" as first argument (pos 0 of possible arg)
+ if( !pArgThreadGroup->GetFound() )
+ return MIstatus::success;
+ m_bIsI1 = true;
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+
+ // Note do not check for rProcess is IsValid(), continue
+
+ m_vecMIValueTuple.clear();
+ const MIuint nThreads = rProcess.GetNumThreads();
+ for( MIuint i = 0; i < nThreads; i++ )
+ {
+ // GetThreadAtIndex() uses a base 0 index
+ // GetThreadByIndexID() uses a base 1 index
+ lldb::SBThread thread = rProcess.GetThreadAtIndex( i );
+
+ if( thread.IsValid() )
+ {
+ CMICmnMIValueTuple miTuple;
+ if( !rSessionInfo.MIResponseFormThreadInfo2( m_cmdData, thread, miTuple ) )
+ return MIstatus::failure;
+
+ m_vecMIValueTuple.push_back( miTuple );
+ }
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdListThreadGroups::Acknowledge( void )
+{
+ if( m_bHaveArgOption )
+ {
+ if( m_bHaveArgRecurse )
+ {
+ const CMICmnMIValueConst miValueConst( MIRSRC( IDS_WORD_NOT_IMPLEMENTED_BRKTS ) );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+ }
+
+ const CMICmnMIValueConst miValueConst1( "i1" );
+ const CMICmnMIValueResult miValueResult1( "id", miValueConst1 );
+ CMICmnMIValueTuple miTuple( miValueResult1 );
+
+ const CMICmnMIValueConst miValueConst2( "process" );
+ const CMICmnMIValueResult miValueResult2( "type", miValueConst2 );
+ miTuple.Add( miValueResult2 );
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ if (rSessionInfo.m_lldbProcess.IsValid ())
+ {
+ const lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID();
+ const CMIUtilString strPid( CMIUtilString::Format( "%lld", pid ) );
+ const CMICmnMIValueConst miValueConst3( strPid );
+ const CMICmnMIValueResult miValueResult3( "pid", miValueConst3 );
+ miTuple.Add( miValueResult3 );
+ }
+
+ const CMICmnMIValueConst miValueConst4( MIRSRC( IDS_WORD_NOT_IMPLEMENTED_BRKTS ) );
+ const CMICmnMIValueResult miValueResult4( "num_children", miValueConst4 );
+ miTuple.Add( miValueResult4 );
+
+ const CMICmnMIValueConst miValueConst5( MIRSRC( IDS_WORD_NOT_IMPLEMENTED_BRKTS ) );
+ const CMICmnMIValueResult miValueResult5( "cores", miValueConst5 );
+ miTuple.Add( miValueResult5 );
+
+ const CMICmnMIValueList miValueList( miTuple );
+ const CMICmnMIValueResult miValueResult6( "groups", miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult6 );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+ }
+
+ if( !m_bIsI1 )
+ {
+ const CMICmnMIValueConst miValueConst1( "i1" );
+ const CMICmnMIValueResult miValueResult1( "id", miValueConst1 );
+ CMICmnMIValueTuple miTuple( miValueResult1 );
+
+ const CMICmnMIValueConst miValueConst2( "process" );
+ const CMICmnMIValueResult miValueResult2( "type", miValueConst2 );
+ miTuple.Add( miValueResult2 );
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ if (rSessionInfo.m_lldbProcess.IsValid ())
+ {
+ const lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID();
+ const CMIUtilString strPid( CMIUtilString::Format( "%lld", pid ) );
+ const CMICmnMIValueConst miValueConst3( strPid );
+ const CMICmnMIValueResult miValueResult3( "pid", miValueConst3 );
+ miTuple.Add( miValueResult3 );
+ }
+
+ if (rSessionInfo.m_lldbTarget.IsValid ())
+ {
+ lldb::SBTarget & rTrgt = rSessionInfo.m_lldbTarget;
+ const MIchar * pDir = rTrgt.GetExecutable().GetDirectory();
+ const MIchar * pFileName = rTrgt.GetExecutable().GetFilename();
+ const CMIUtilString strFile( CMIUtilString::Format( "%s/%s", pDir, pFileName ) );
+ const CMICmnMIValueConst miValueConst4( strFile );
+ const CMICmnMIValueResult miValueResult4( "executable", miValueConst4 );
+ miTuple.Add( miValueResult4 );
+ }
+
+ const CMICmnMIValueList miValueList( miTuple );
+ const CMICmnMIValueResult miValueResult5( "groups", miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult5 );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ // Build up a list of thread information from tuples
+ VecMIValueTuple_t::const_iterator it = m_vecMIValueTuple.begin();
+ if( it == m_vecMIValueTuple.end() )
+ {
+ const CMICmnMIValueConst miValueConst( "[]" );
+ const CMICmnMIValueResult miValueResult( "threads", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+ CMICmnMIValueList miValueList( *it );
+ ++it;
+ while( it != m_vecMIValueTuple.end() )
+ {
+ const CMICmnMIValueTuple & rTuple( *it );
+ miValueList.Add( rTuple );
+
+ // Next
+ ++it;
+ }
+
+ const CMICmnMIValueResult miValueResult( "threads", miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdListThreadGroups::CreateSelf( void )
+{
+ return new CMICmdCmdListThreadGroups();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdInterpreterExec constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdInterpreterExec::CMICmdCmdInterpreterExec( void )
+: m_constStrArgNamedInterpreter( "intepreter" )
+, m_constStrArgNamedCommand( "command" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "interpreter-exec";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdInterpreterExec::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdInterpreterExec destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdInterpreterExec::~CMICmdCmdInterpreterExec( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdInterpreterExec::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgNamedInterpreter, true, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgNamedCommand, true, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdInterpreterExec::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgInterpreter, String, m_constStrArgNamedInterpreter );
+ CMICMDBASE_GETOPTION( pArgCommand, String, m_constStrArgNamedCommand );
+
+ // Handle the interpreter parameter by do nothing on purpose (set to 'handled' in
+ // the arg definition above)
+ const CMIUtilString & rStrInterpreter( pArgInterpreter->GetValue() ); MIunused( rStrInterpreter );
+
+ const CMIUtilString & rStrCommand( pArgCommand->GetValue() );
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ const lldb::ReturnStatus rtn = rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand( rStrCommand.c_str(), m_lldbResult, true ); MIunused( rtn );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdInterpreterExec::Acknowledge( void )
+{
+ if( m_lldbResult.GetOutputSize() > 0 )
+ {
+ CMIUtilString strMsg( m_lldbResult.GetOutput() );
+ strMsg = strMsg.StripCREndOfLine();
+ CMICmnStreamStdout::TextToStdout( strMsg );
+
+ // Send the LLDB result message to console so the user can see the result of the
+ // command they typed. It is not necessary an error message.
+ CMICmnStreamStderr::LLDBMsgToConsole( strMsg );
+ }
+ if( m_lldbResult.GetErrorSize() > 0 )
+ {
+ CMIUtilString strMsg( m_lldbResult.GetError() );
+ strMsg = strMsg.StripCREndOfLine();
+ CMICmnStreamStderr::LLDBMsgToConsole( strMsg );
+
+ // Send LLDB's error message to the MI Driver's Log file
+ CMICmnStreamStdout::TextToStdout( strMsg );
+ }
+
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdInterpreterExec::CreateSelf( void )
+{
+ return new CMICmdCmdInterpreterExec();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdInferiorTtySet constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdInferiorTtySet::CMICmdCmdInferiorTtySet( void )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "inferior-tty-set";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdInferiorTtySet::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdInferiorTtySet destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdInferiorTtySet::~CMICmdCmdInferiorTtySet( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdInferiorTtySet::Execute( void )
+{
+ // Do nothing
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdInferiorTtySet::Acknowledge( void )
+{
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdInferiorTtySet::CreateSelf( void )
+{
+ return new CMICmdCmdInferiorTtySet();
+}
diff --git a/tools/lldb-mi/MICmdCmdMiscellanous.h b/tools/lldb-mi/MICmdCmdMiscellanous.h
new file mode 100644
index 000000000000..ea71f1233418
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdMiscellanous.h
@@ -0,0 +1,175 @@
+//===-- MICmdCmdMiscellanous.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdMiscellanous.h
+//
+// Overview: CMICmdCmdGdbExit interface.
+// CMICmdCmdListThreadGroups interface.
+// CMICmdCmdInterpreterExec interface.
+// CMICmdCmdInferiorTtySet interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <lldb/API/SBCommandReturnObject.h>
+
+// In-house headers:
+#include "MICmdBase.h"
+#include "MICmnMIValueTuple.h"
+#include "MICmnMIValueList.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "gdb-exit".
+// Gotchas: None.
+// Authors: Illya Rudkin 04/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdGdbExit : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdGdbExit( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdGdbExit( void );
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "list-thread-groups".
+// This command does not follow the MI documentation exactly.
+// http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Miscellaneous-Commands.html#GDB_002fMI-Miscellaneous-Commands
+// Gotchas: None.
+// Authors: Illya Rudkin 06/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdListThreadGroups : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdListThreadGroups( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdListThreadGroups( void );
+
+// Typedefs:
+private:
+ typedef std::vector< CMICmnMIValueTuple > VecMIValueTuple_t;
+
+// Attributes:
+private:
+ bool m_bIsI1; // True = Yes command argument equal "i1", false = no match
+ bool m_bHaveArgOption; // True = Yes "--available" present, false = not found
+ bool m_bHaveArgRecurse; // True = Yes command argument "--recurse", false = no found
+ VecMIValueTuple_t m_vecMIValueTuple;
+ const CMIUtilString m_constStrArgNamedAvailable;
+ const CMIUtilString m_constStrArgNamedRecurse;
+ const CMIUtilString m_constStrArgNamedGroup;
+ const CMIUtilString m_constStrArgNamedThreadGroup;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "interpreter-exec".
+// Gotchas: None.
+// Authors: Illya Rudkin 16/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdInterpreterExec : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdInterpreterExec( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdInterpreterExec( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgNamedInterpreter;
+ const CMIUtilString m_constStrArgNamedCommand;
+ lldb::SBCommandReturnObject m_lldbResult;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "inferior-tty-set".
+// Gotchas: None.
+// Authors: Illya Rudkin 22/07/2014.
+// Changes: None.
+//--
+class CMICmdCmdInferiorTtySet : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdInferiorTtySet( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdInferiorTtySet( void );
+}; \ No newline at end of file
diff --git a/tools/lldb-mi/MICmdCmdStack.cpp b/tools/lldb-mi/MICmdCmdStack.cpp
new file mode 100644
index 000000000000..5f5b355758c4
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdStack.cpp
@@ -0,0 +1,634 @@
+//===-- MICmdCmdStack.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdStack.cpp
+//
+// Overview: CMICmdCmdStackInfoDepth implementation.
+// CMICmdCmdStackListFrames implementation.
+// CMICmdCmdStackListArguments implementation.
+// CMICmdCmdStackListLocals implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third Party Headers:
+#include <lldb/API/SBThread.h>
+
+// In-house headers:
+#include "MICmdCmdStack.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnMIOutOfBandRecord.h"
+#include "MICmnLLDBDebugger.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MICmdArgValNumber.h"
+#include "MICmdArgValString.h"
+#include "MICmdArgValThreadGrp.h"
+#include "MICmdArgValOptionLong.h"
+#include "MICmdArgValOptionShort.h"
+#include "MICmdArgValListOfN.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackInfoDepth constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackInfoDepth::CMICmdCmdStackInfoDepth( void )
+: m_nThreadFrames( 0 )
+, m_constStrArgThread( "thread" )
+, m_constStrArgMaxDepth( "max-depth" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "stack-info-depth";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdStackInfoDepth::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackInfoDepth destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackInfoDepth::~CMICmdCmdStackInfoDepth( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdStackInfoDepth::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgMaxDepth, false, false ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdStackInfoDepth::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
+ CMICMDBASE_GETOPTION( pArgMaxDepth, Number, m_constStrArgMaxDepth );
+
+ // Retrieve the --thread option's thread ID (only 1)
+ MIuint64 nThreadId = UINT64_MAX;
+ if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID( nThreadId ) : rProcess.GetSelectedThread();
+ m_nThreadFrames = thread.GetNumFrames();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdStackInfoDepth::Acknowledge( void )
+{
+ const CMIUtilString strDepth( CMIUtilString::Format( "%d", m_nThreadFrames ) );
+ const CMICmnMIValueConst miValueConst( strDepth );
+ const CMICmnMIValueResult miValueResult( "depth", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdStackInfoDepth::CreateSelf( void )
+{
+ return new CMICmdCmdStackInfoDepth();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackListFrames constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackListFrames::CMICmdCmdStackListFrames( void )
+: m_nThreadFrames( 0 )
+, m_constStrArgThread( "thread" )
+, m_constStrArgFrameLow( "low-frame" )
+, m_constStrArgFrameHigh( "high-frame" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "stack-list-frames";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdStackListFrames::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackListFrames destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackListFrames::~CMICmdCmdStackListFrames( void )
+{
+ m_vecMIValueResult.clear();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdStackListFrames::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgFrameLow, false, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgFrameHigh, false, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdStackListFrames::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
+ CMICMDBASE_GETOPTION( pArgFrameLow, Number, m_constStrArgFrameLow );
+ CMICMDBASE_GETOPTION( pArgFrameHigh, Number, m_constStrArgFrameHigh );
+
+ // Retrieve the --thread option's thread ID (only 1)
+ MIuint64 nThreadId = UINT64_MAX;
+ if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ // Frame low and high options are not mandatory
+ MIuint nFrameHigh = pArgFrameHigh->GetFound() ? pArgFrameHigh->GetValue() : UINT64_MAX;
+ const MIuint nFrameLow = pArgFrameLow->GetFound() ? pArgFrameLow->GetValue() : 0;
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID( nThreadId ) : rProcess.GetSelectedThread();
+ MIuint nThreadFrames = thread.GetNumFrames();
+
+ // Adjust nThreadFrames for the nFrameHigh argument as we use nFrameHigh+1 in the min calc as the arg
+ // is not an index, but a frame id value.
+ if( nFrameHigh < UINT32_MAX )
+ {
+ nFrameHigh++;
+ nThreadFrames = (nFrameHigh < nThreadFrames) ? nFrameHigh : nThreadFrames;
+ }
+
+ m_nThreadFrames = nThreadFrames;
+ if( nThreadFrames == 0 )
+ return MIstatus::success;
+
+ m_vecMIValueResult.clear();
+ for( MIuint nLevel = nFrameLow; nLevel < nThreadFrames; nLevel++ )
+ {
+ CMICmnMIValueTuple miValueTuple;
+ if( !rSessionInfo.MIResponseFormFrameInfo( thread, nLevel, miValueTuple ) )
+ return MIstatus::failure;
+
+ const CMICmnMIValueResult miValueResult8( "frame", miValueTuple );
+ m_vecMIValueResult.push_back( miValueResult8 );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdStackListFrames::Acknowledge( void )
+{
+ if( m_nThreadFrames == 0 )
+ {
+ // MI print "3^done,stack=[{}]"
+ const CMICmnMIValueTuple miValueTuple;
+ const CMICmnMIValueList miValueList( miValueTuple );
+ const CMICmnMIValueResult miValueResult( "stack", miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+ }
+
+ // Build up a list of thread information from tuples
+ VecMIValueResult_t::const_iterator it = m_vecMIValueResult.begin();
+ if( it == m_vecMIValueResult.end() )
+ {
+ // MI print "3^done,stack=[{}]"
+ const CMICmnMIValueTuple miValueTuple;
+ const CMICmnMIValueList miValueList( miValueTuple );
+ const CMICmnMIValueResult miValueResult( "stack", miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+ CMICmnMIValueList miValueList( *it );
+ ++it;
+ while( it != m_vecMIValueResult.end() )
+ {
+ const CMICmnMIValueResult & rTuple( *it );
+ miValueList.Add( rTuple );
+
+ // Next
+ ++it;
+ }
+ const CMICmnMIValueResult miValueResult( "stack", miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdStackListFrames::CreateSelf( void )
+{
+ return new CMICmdCmdStackListFrames();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackListArguments constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackListArguments::CMICmdCmdStackListArguments( void )
+: m_bThreadInvalid( false )
+, m_miValueList( true )
+, m_constStrArgThread( "thread" )
+, m_constStrArgPrintValues( "print-values" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "stack-list-arguments";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdStackListArguments::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackListArguments destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackListArguments::~CMICmdCmdStackListArguments( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdStackListArguments::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgPrintValues, true, false ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdStackListArguments::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
+ CMICMDBASE_GETOPTION( pArgPrintValues, Number, m_constStrArgPrintValues );
+
+ // Retrieve the --thread option's thread ID (only 1)
+ MIuint64 nThreadId = UINT64_MAX;
+ if( pArgThread->GetFound() )
+ {
+ if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
+ return MIstatus::failure;
+ }
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID( nThreadId ) : rProcess.GetSelectedThread();
+ m_bThreadInvalid = !thread.IsValid();
+ if( m_bThreadInvalid )
+ return MIstatus::success;
+
+ const lldb::StopReason eStopReason = thread.GetStopReason();
+ if( (eStopReason == lldb::eStopReasonNone) || (eStopReason == lldb::eStopReasonInvalid) )
+ {
+ m_bThreadInvalid = true;
+ return MIstatus::success;
+ }
+
+
+ const MIuint nFrames = thread.GetNumFrames();
+ for( MIuint i = 0; i < nFrames; i++ )
+ {
+ lldb::SBFrame frame = thread.GetFrameAtIndex( i );
+ CMICmnMIValueList miValueList( true );
+ const MIuint maskVarTypes = 0x1000;
+ if( !rSessionInfo.MIResponseFormVariableInfo3( frame, maskVarTypes, miValueList ) )
+ return MIstatus::failure;
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "%d", i ) );
+ const CMICmnMIValueResult miValueResult( "level", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ const CMICmnMIValueResult miValueResult2( "args", miValueList );
+ miValueTuple.Add( miValueResult2 );
+ const CMICmnMIValueResult miValueResult3( "frame", miValueTuple );
+ m_miValueList.Add( miValueResult3 );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdStackListArguments::Acknowledge( void )
+{
+ if( m_bThreadInvalid )
+ {
+ // MI print "%s^done,stack-args=[]"
+ const CMICmnMIValueList miValueList( true );
+ const CMICmnMIValueResult miValueResult( "stack-args", miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ // MI print "%s^done,stack-args=[frame={level=\"0\",args=[%s]},frame={level=\"1\",args=[%s]}]"
+ const CMICmnMIValueResult miValueResult4( "stack-args", m_miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult4 );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdStackListArguments::CreateSelf( void )
+{
+ return new CMICmdCmdStackListArguments();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackListLocals constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackListLocals::CMICmdCmdStackListLocals( void )
+: m_bThreadInvalid( false )
+, m_miValueList( true )
+, m_constStrArgThread( "thread" )
+, m_constStrArgFrame( "frame" )
+, m_constStrArgPrintValues( "print-values" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "stack-list-locals";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdStackListLocals::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdStackListLocals destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdStackListLocals::~CMICmdCmdStackListLocals( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdStackListLocals::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgFrame, false, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgPrintValues, true, false ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdStackListLocals::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
+ CMICMDBASE_GETOPTION( pArgFrame, OptionLong, m_constStrArgFrame );
+
+ // Retrieve the --thread option's thread ID (only 1)
+ MIuint64 nThreadId = UINT64_MAX;
+ if( pArgThread->GetFound() )
+ {
+ if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
+ return MIstatus::failure;
+ }
+ }
+ MIuint64 nFrame = UINT64_MAX;
+ if( pArgFrame->GetFound() )
+ {
+ if( !pArgFrame->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nFrame ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgFrame.c_str() ) );
+ return MIstatus::failure;
+ }
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID( nThreadId ) : rProcess.GetSelectedThread();
+ m_bThreadInvalid = !thread.IsValid();
+ if( m_bThreadInvalid )
+ return MIstatus::success;
+
+ const lldb::StopReason eStopReason = thread.GetStopReason();
+ if( (eStopReason == lldb::eStopReasonNone) || (eStopReason == lldb::eStopReasonInvalid) )
+ {
+ m_bThreadInvalid = true;
+ return MIstatus::success;
+ }
+
+ const MIuint nFrames = thread.GetNumFrames(); MIunused( nFrames );
+ lldb::SBFrame frame = (nFrame != UINT64_MAX) ? thread.GetFrameAtIndex( nFrame ) : thread.GetSelectedFrame();
+ CMICmnMIValueList miValueList( true );
+ const MIuint maskVarTypes = 0x0110;
+ if( !rSessionInfo.MIResponseFormVariableInfo( frame, maskVarTypes, miValueList ) )
+ return MIstatus::failure;
+
+ m_miValueList = miValueList;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdStackListLocals::Acknowledge( void )
+{
+ if( m_bThreadInvalid )
+ {
+ // MI print "%s^done,locals=[]"
+ const CMICmnMIValueList miValueList( true );
+ const CMICmnMIValueResult miValueResult( "locals", miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ // MI print "%s^done,locals=[%s]"
+ const CMICmnMIValueResult miValueResult( "locals", m_miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdStackListLocals::CreateSelf( void )
+{
+ return new CMICmdCmdStackListLocals();
+}
+
diff --git a/tools/lldb-mi/MICmdCmdStack.h b/tools/lldb-mi/MICmdCmdStack.h
new file mode 100644
index 000000000000..0c3a291d5870
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdStack.h
@@ -0,0 +1,184 @@
+//===-- MICmdCmdStack.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdStack.h
+//
+// Overview: CMICmdCmdStackInfoDepth interface.
+// CMICmdCmdStackListFrames interface.
+// CMICmdCmdStackListArguments interface.
+// CMICmdCmdStackListLocals interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdBase.h"
+#include "MICmnMIValueList.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "stack-info-depth".
+// Gotchas: None.
+// Authors: Illya Rudkin 21/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdStackInfoDepth : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdStackInfoDepth( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdStackInfoDepth( void );
+
+// Attributes:
+private:
+ MIuint m_nThreadFrames;
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgMaxDepth; // Not handled by *this command
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "stack-list-frames".
+// Gotchas: None.
+// Authors: Illya Rudkin 21/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdStackListFrames : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdStackListFrames( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdStackListFrames( void );
+
+// Typedefs:
+private:
+ typedef std::vector< CMICmnMIValueResult > VecMIValueResult_t;
+
+// Attributes:
+private:
+ MIuint m_nThreadFrames;
+ VecMIValueResult_t m_vecMIValueResult;
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgFrameLow;
+ const CMIUtilString m_constStrArgFrameHigh;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "stack-list-arguments".
+// Gotchas: None.
+// Authors: Illya Rudkin 24/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdStackListArguments : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdStackListArguments( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdStackListArguments( void );
+
+// Attributes:
+private:
+ bool m_bThreadInvalid; // True = yes invalid thread, false = thread object valid
+ CMICmnMIValueList m_miValueList;
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgPrintValues; // Not handled by *this command
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "stack-list-locals".
+// Gotchas: None.
+// Authors: Illya Rudkin 24/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdStackListLocals : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdStackListLocals( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdStackListLocals( void );
+
+// Attributes:
+private:
+ bool m_bThreadInvalid; // True = yes invalid thread, false = thread object valid
+ CMICmnMIValueList m_miValueList;
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgFrame; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgPrintValues; // Not handled by *this command
+};
+
diff --git a/tools/lldb-mi/MICmdCmdSupportInfo.cpp b/tools/lldb-mi/MICmdCmdSupportInfo.cpp
new file mode 100644
index 000000000000..e6f96f094e58
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdSupportInfo.cpp
@@ -0,0 +1,129 @@
+//===-- MICmdCmdSupportListInfo.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdSupportListInfo.cpp
+//
+// Overview: CMICmdCmdSupportInfoMiCmdQuery implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdCmdSupportInfo.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnMIValueTuple.h"
+#include "MICmdArgValString.h"
+#include "MICmdFactory.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdSupportInfoMiCmdQuery constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdSupportInfoMiCmdQuery::CMICmdCmdSupportInfoMiCmdQuery( void )
+: m_bCmdFound( false )
+, m_constStrArgCmdName( "cmd_name" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "info-gdb-mi-command";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdSupportInfoMiCmdQuery::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdSupportInfoMiCmdQuery destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdSupportInfoMiCmdQuery::~CMICmdCmdSupportInfoMiCmdQuery( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdSupportInfoMiCmdQuery::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgCmdName, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdSupportInfoMiCmdQuery::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgNamedCmdName, String, m_constStrArgCmdName );
+ const CMIUtilString & rCmdToQuery( pArgNamedCmdName->GetValue() );
+ const MIuint nLen = rCmdToQuery.length();
+ const CMICmdFactory & rCmdFactory = CMICmdFactory::Instance();
+ if( (nLen > 1) && (rCmdToQuery[ 0 ] == '-') )
+ m_bCmdFound = rCmdFactory.CmdExist( rCmdToQuery.substr( 1, nLen - 1 ).c_str() );
+ else
+ m_bCmdFound = rCmdFactory.CmdExist( rCmdToQuery );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdSupportInfoMiCmdQuery::Acknowledge( void )
+{
+ const CMICmnMIValueConst miValueConst( m_bCmdFound ? "true" : "false" );
+ const CMICmnMIValueResult miValueResult( "exists", miValueConst );
+ const CMICmnMIValueTuple miValueTuple( miValueResult );
+ const CMICmnMIValueResult miValueResult2( "command", miValueTuple );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult2 );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdSupportInfoMiCmdQuery::CreateSelf( void )
+{
+ return new CMICmdCmdSupportInfoMiCmdQuery();
+}
diff --git a/tools/lldb-mi/MICmdCmdSupportInfo.h b/tools/lldb-mi/MICmdCmdSupportInfo.h
new file mode 100644
index 000000000000..2633e99ce10e
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdSupportInfo.h
@@ -0,0 +1,69 @@
+//===-- MICmdCmdSupportInfo.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdSupportInfo.h
+//
+// Overview: CMICmdCmdSupportInfoMiCmdQuery interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdBase.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "info-gdb-mi-command".
+// This command does not follow the MI documentation exactly.
+// Gotchas: None.
+// Authors: Illya Rudkin 06/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdSupportInfoMiCmdQuery : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdSupportInfoMiCmdQuery( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdSupportInfoMiCmdQuery( void );
+
+// Attributes:
+private:
+ bool m_bCmdFound; // True = query for the command in command factory found, false = not found not recognised
+ const CMIUtilString m_constStrArgCmdName;
+};
+
diff --git a/tools/lldb-mi/MICmdCmdSupportList.cpp b/tools/lldb-mi/MICmdCmdSupportList.cpp
new file mode 100644
index 000000000000..2e4beb3edc85
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdSupportList.cpp
@@ -0,0 +1,102 @@
+//===-- MICmdCmdSupportList.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdSupportList.cpp
+//
+// Overview: CMICmdCmdSupportListFeatures implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdCmdSupportList.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnMIValueList.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdSupportListFeatures constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdSupportListFeatures::CMICmdCmdSupportListFeatures( void )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "list-features";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdSupportListFeatures::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdSupportListFeatures destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdSupportListFeatures::~CMICmdCmdSupportListFeatures( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdSupportListFeatures::Execute( void )
+{
+ // Do nothing
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdSupportListFeatures::Acknowledge( void )
+{
+ const CMICmnMIValueConst miValueConst( "data-read-memory-bytes" );
+ const CMICmnMIValueList miValueList( miValueConst );
+ const CMICmnMIValueResult miValueResult( "features", miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdSupportListFeatures::CreateSelf( void )
+{
+ return new CMICmdCmdSupportListFeatures();
+}
diff --git a/tools/lldb-mi/MICmdCmdSupportList.h b/tools/lldb-mi/MICmdCmdSupportList.h
new file mode 100644
index 000000000000..d9909a88997f
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdSupportList.h
@@ -0,0 +1,63 @@
+//===-- MICmdCmdSupportList.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdSupportList.h
+//
+// Overview: CMICmdCmdSupportListFeatures interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdBase.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "list-features".
+// This command does not follow the MI documentation exactly.
+// Gotchas: None.
+// Authors: Illya Rudkin 03/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdSupportListFeatures : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdSupportListFeatures( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdSupportListFeatures( void );
+};
+
diff --git a/tools/lldb-mi/MICmdCmdTarget.cpp b/tools/lldb-mi/MICmdCmdTarget.cpp
new file mode 100644
index 000000000000..60c1c5e4bba2
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdTarget.cpp
@@ -0,0 +1,217 @@
+//===-- MICmdCmdTarget.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdTarget.cpp
+//
+// Overview: CMICmdCmdTargetSelect implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third Party Headers:
+#include <lldb/API/SBStream.h>
+#include <lldb/API/SBCommandInterpreter.h>
+#include <lldb/API/SBCommandReturnObject.h>
+
+// In-house headers:
+#include "MICmdCmdTarget.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnMIOutOfBandRecord.h"
+#include "MICmnLLDBDebugger.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MICmdArgValString.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdTargetSelect constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdTargetSelect::CMICmdCmdTargetSelect( void )
+: m_constStrArgNamedType( "type" )
+, m_constStrArgNamedParameters( "parameters" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "target-select";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdTargetSelect::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdTargetSelect destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdTargetSelect::~CMICmdCmdTargetSelect( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdTargetSelect::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgNamedType, true, true )) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgNamedParameters, true, true )) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Synopsis: -target-select type parameters ...
+// Ref: http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdTargetSelect::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgType, String, m_constStrArgNamedType );
+ CMICMDBASE_GETOPTION( pArgParameters, String, m_constStrArgNamedParameters );
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+
+ // Check we have a valid target
+ // Note: target created via 'file-exec-and-symbols' command
+ if( !rSessionInfo.m_lldbTarget.IsValid() )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_TARGET_CURRENT ), m_cmdData.strMiCmd.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ // Verify that we are executing remotely
+ const CMIUtilString & rRemoteType( pArgType->GetValue() );
+ if( rRemoteType != "remote" )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_TARGET_TYPE ), m_cmdData.strMiCmd.c_str(), rRemoteType.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ // Create a URL pointing to the remote gdb stub
+ const CMIUtilString strUrl = CMIUtilString::Format( "connect://%s", pArgParameters->GetValue().c_str() );
+
+ // Ask LLDB to collect to the target port
+ const MIchar * pPlugin( "gdb-remote" );
+ lldb::SBError error;
+ lldb::SBProcess process = rSessionInfo.m_lldbTarget.ConnectRemote( rSessionInfo.m_rLlldbListener, strUrl.c_str(), pPlugin, error );
+
+ // Verify that we have managed to connect successfully
+ lldb::SBStream errMsg;
+ if( !process.IsValid() )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_INVALID_TARGET_PLUGIN ), m_cmdData.strMiCmd.c_str(), errMsg.GetData() ) );
+ return MIstatus::failure;
+ }
+ if( error.Fail() )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_CONNECT_TO_TARGET ), m_cmdData.strMiCmd.c_str(), errMsg.GetData() ) );
+ return MIstatus::failure;
+ }
+
+ // Save the process in the session info
+ // Note: Order is important here since this process handle may be used by CMICmnLLDBDebugHandleEvents
+ // which can fire when interpreting via HandleCommand() below.
+ rSessionInfo.m_lldbProcess = process;
+
+ // Set the environment path if we were given one
+ CMIUtilString strWkDir;
+ if( rSessionInfo.SharedDataRetrieve< CMIUtilString >( rSessionInfo.m_constStrSharedDataKeyWkDir, strWkDir ) )
+ {
+ lldb::SBDebugger & rDbgr = rSessionInfo.m_rLldbDebugger;
+ if( !rDbgr.SetCurrentPlatformSDKRoot( strWkDir.c_str() ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_FNFAILED ), m_cmdData.strMiCmd.c_str(), "target-select" ) );
+ return MIstatus::failure;
+ }
+ }
+
+ // Set the shared object path if we were given one
+ CMIUtilString strSolibPath;
+ if( rSessionInfo.SharedDataRetrieve< CMIUtilString >( rSessionInfo.m_constStrSharedDataSolibPath, strSolibPath ) )
+ {
+ lldb::SBDebugger & rDbgr = rSessionInfo.m_rLldbDebugger;
+ lldb::SBCommandInterpreter cmdIterpreter = rDbgr.GetCommandInterpreter();
+
+ CMIUtilString strCmdString = CMIUtilString::Format( "target modules search-paths add . %s", strSolibPath.c_str() );
+
+ lldb::SBCommandReturnObject retObj;
+ cmdIterpreter.HandleCommand( strCmdString.c_str(), retObj, false );
+
+ if( !retObj.Succeeded() )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_FNFAILED ), m_cmdData.strMiCmd.c_str(), "target-select" ) );
+ return MIstatus::failure;
+ }
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdTargetSelect::Acknowledge( void )
+{
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Connected );
+ m_miResultRecord = miRecordResult;
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID();
+ // Prod the client i.e. Eclipse with out-of-band results to help it 'continue' because it is using LLDB debugger
+ // Give the client '=thread-group-started,id="i1"'
+ m_bHasResultRecordExtra = true;
+ const CMICmnMIValueConst miValueConst2( "i1" );
+ const CMICmnMIValueResult miValueResult2( "id", miValueConst2 );
+ const CMIUtilString strPid( CMIUtilString::Format( "%lld", pid ) );
+ const CMICmnMIValueConst miValueConst( strPid );
+ const CMICmnMIValueResult miValueResult( "pid", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBand( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, miValueResult2 );
+ miOutOfBand.Add( miValueResult );
+ m_miResultRecordExtra = miOutOfBand.GetString();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdTargetSelect::CreateSelf( void )
+{
+ return new CMICmdCmdTargetSelect();
+}
diff --git a/tools/lldb-mi/MICmdCmdTarget.h b/tools/lldb-mi/MICmdCmdTarget.h
new file mode 100644
index 000000000000..f904f20ee4f6
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdTarget.h
@@ -0,0 +1,70 @@
+//===-- MICmdCmdTarget.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdTarget.h
+//
+// Overview: CMICmdCmdTargetSelect interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdBase.h"
+#include "MICmnMIValueTuple.h"
+#include "MICmnMIValueList.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "target-select".
+// http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
+// Gotchas: None.
+// Authors: Illya Rudkin 05/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdTargetSelect : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdTargetSelect( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdTargetSelect( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgNamedType;
+ const CMIUtilString m_constStrArgNamedParameters;
+};
diff --git a/tools/lldb-mi/MICmdCmdThread.cpp b/tools/lldb-mi/MICmdCmdThread.cpp
new file mode 100644
index 000000000000..8cfaae804931
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdThread.cpp
@@ -0,0 +1,207 @@
+//===-- MICmdCmdThread.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdThread.cpp
+//
+// Overview: CMICmdCmdThreadInfo implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third Party Headers:
+#include <lldb/API/SBBreakpointLocation.h>
+#include <lldb/API/SBThread.h>
+
+// In-house headers:
+#include "MICmdCmdThread.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnLLDBDebugger.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MICmdArgValNumber.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdThreadInfo constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdThreadInfo::CMICmdCmdThreadInfo( void )
+: m_bSingleThread( false )
+, m_bThreadInvalid( true )
+, m_constStrArgNamedThreadId( "thread-id" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "thread-info";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdThreadInfo::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdThreadInfo destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdThreadInfo::~CMICmdCmdThreadInfo( void )
+{
+ m_vecMIValueTuple.clear();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdThreadInfo::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgNamedThreadId, false, true )) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdThreadInfo::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgThreadId, Number, m_constStrArgNamedThreadId );
+ MIuint nThreadId = 0;
+ if( pArgThreadId->GetFound() && pArgThreadId->GetValid() )
+ {
+ m_bSingleThread = true;
+ nThreadId = static_cast< MIuint >( pArgThreadId->GetValue() );
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+ lldb::SBThread thread = rProcess.GetSelectedThread();
+
+ if( m_bSingleThread )
+ {
+ thread = rProcess.GetThreadByIndexID( nThreadId );
+ m_bThreadInvalid = thread.IsValid();
+ if( !m_bThreadInvalid )
+ return MIstatus::success;
+
+ CMICmnMIValueTuple miTuple;
+ if( !rSessionInfo.MIResponseFormThreadInfo3( m_cmdData, thread, miTuple ) )
+ return MIstatus::failure;
+
+ m_miValueTupleThread = miTuple;
+
+ return MIstatus::success;
+ }
+
+ // Multiple threads
+ m_vecMIValueTuple.clear();
+ const MIuint nThreads = rProcess.GetNumThreads();
+ for( MIuint i = 0; i < nThreads; i++ )
+ {
+ lldb::SBThread thread = rProcess.GetThreadAtIndex( i );
+ if( thread.IsValid() )
+ {
+ CMICmnMIValueTuple miTuple;
+ if( !rSessionInfo.MIResponseFormThreadInfo3( m_cmdData, thread, miTuple ) )
+ return MIstatus::failure;
+
+ m_vecMIValueTuple.push_back( miTuple );
+ }
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdThreadInfo::Acknowledge( void )
+{
+ if( m_bSingleThread )
+ {
+ if( !m_bThreadInvalid )
+ {
+ const CMICmnMIValueConst miValueConst( "invalid thread id" );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ // MI print "%s^done,threads=[{id=\"%d\",target-id=\"%s\",frame={},state=\"%s\"}]
+ const CMICmnMIValueList miValueList( m_miValueTupleThread );
+ const CMICmnMIValueResult miValueResult( "threads", miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ // Build up a list of thread information from tuples
+ VecMIValueTuple_t::const_iterator it = m_vecMIValueTuple.begin();
+ if( it == m_vecMIValueTuple.end() )
+ {
+ const CMICmnMIValueConst miValueConst( "[]" );
+ const CMICmnMIValueResult miValueResult( "threads", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+ CMICmnMIValueList miValueList( *it );
+ ++it;
+ while( it != m_vecMIValueTuple.end() )
+ {
+ const CMICmnMIValueTuple & rTuple( *it );
+ miValueList.Add( rTuple );
+
+ // Next
+ ++it;
+ }
+
+ const CMICmnMIValueResult miValueResult( "threads", miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdThreadInfo::CreateSelf( void )
+{
+ return new CMICmdCmdThreadInfo();
+}
diff --git a/tools/lldb-mi/MICmdCmdThread.h b/tools/lldb-mi/MICmdCmdThread.h
new file mode 100644
index 000000000000..33cd786a8cac
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdThread.h
@@ -0,0 +1,76 @@
+//===-- MICmdCmdThread.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdThread.h
+//
+// Overview: CMICmdCmdThreadInfo interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdBase.h"
+#include "MICmnMIValueTuple.h"
+#include "MICmnMIValueList.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "thread-info".
+// Gotchas: None.
+// Authors: Illya Rudkin 07/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdThreadInfo : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdThreadInfo( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdThreadInfo( void );
+
+// Typedefs:
+private:
+ typedef std::vector< CMICmnMIValueTuple > VecMIValueTuple_t;
+
+// Attributes:
+private:
+ CMICmnMIValueTuple m_miValueTupleThread;
+ bool m_bSingleThread; // True = yes single thread, false = multiple threads
+ bool m_bThreadInvalid; // True = invalid, false = ok
+ VecMIValueTuple_t m_vecMIValueTuple;
+ const CMIUtilString m_constStrArgNamedThreadId;
+};
diff --git a/tools/lldb-mi/MICmdCmdTrace.cpp b/tools/lldb-mi/MICmdCmdTrace.cpp
new file mode 100644
index 000000000000..8623db9eb151
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdTrace.cpp
@@ -0,0 +1,99 @@
+//===-- MICmdCmdTrace.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdTrace.cpp
+//
+// Overview: CMICmdCmdTraceStatus implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdCmdTrace.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdTraceStatus constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdTraceStatus::CMICmdCmdTraceStatus( void )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "trace-status";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdTraceStatus::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdTraceStatus destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdTraceStatus::~CMICmdCmdTraceStatus( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdTraceStatus::Execute( void )
+{
+ // Do nothing
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdTraceStatus::Acknowledge( void )
+{
+ const CMICmnMIValueConst miValueConst( MIRSRC( IDS_CMD_ERR_NOT_IMPLEMENTED ) );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdTraceStatus::CreateSelf( void )
+{
+ return new CMICmdCmdTraceStatus();
+}
diff --git a/tools/lldb-mi/MICmdCmdTrace.h b/tools/lldb-mi/MICmdCmdTrace.h
new file mode 100644
index 000000000000..2192d007a599
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdTrace.h
@@ -0,0 +1,61 @@
+//===-- MICmdCmdTrace.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdTrace.h
+//
+// Overview: CMICmdCmdTraceStatus interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdBase.h"
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "trace-status".
+// Gotchas: None.
+// Authors: Illya Rudkin 07/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdTraceStatus : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdTraceStatus( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdTraceStatus( void );
+};
diff --git a/tools/lldb-mi/MICmdCmdVar.cpp b/tools/lldb-mi/MICmdCmdVar.cpp
new file mode 100644
index 000000000000..346d69600760
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdVar.cpp
@@ -0,0 +1,1492 @@
+//===-- MICmdCmdVar.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdVar.cpp
+//
+// Overview: CMICmdCmdVarCreate implementation.
+// CMICmdCmdVarUpdate implementation.
+// CMICmdCmdVarDelete implementation.
+// CMICmdCmdVarAssign implementation.
+// CMICmdCmdVarSetFormat implementation.
+// CMICmdCmdVarListChildren implementation.
+// CMICmdCmdVarEvaluateExpression implementation.
+// CMICmdCmdVarInfoPathExpression implementation.
+// CMICmdCmdVarShowAttributes implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third Party Headers:
+#include <lldb/API/SBStream.h>
+#include <lldb/API/SBThread.h>
+
+// In-house headers:
+#include "MICmdCmdVar.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnLLDBDebugger.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MICmdArgValNumber.h"
+#include "MICmdArgValString.h"
+#include "MICmdArgValThreadGrp.h"
+#include "MICmdArgValOptionLong.h"
+#include "MICmdArgValOptionShort.h"
+#include "MICmdArgValListOfN.h"
+#include "MICmnLLDBProxySBValue.h"
+#include "MICmnLLDBUtilSBValue.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarCreate constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarCreate::CMICmdCmdVarCreate( void )
+: m_nChildren( 0 )
+, m_nMore( 0 )
+, m_nThreadId( 0 )
+, m_strType( "??" )
+, m_bValid( false )
+, m_strValue( "??" )
+, m_constStrArgThread( "thread" )
+, m_constStrArgThreadGroup( "thread-group" )
+, m_constStrArgFrame( "frame" )
+, m_constStrArgName( "name" )
+, m_constStrArgFrameAddr( "frame-addr" )
+, m_constStrArgExpression( "expression" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "var-create";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdVarCreate::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarCreate destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarCreate::~CMICmdCmdVarCreate( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarCreate::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgThreadGroup, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValOptionLong( m_constStrArgFrame, false, true, CMICmdArgValListBase::eArgValType_Number, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgName, false, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgFrameAddr, false, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgExpression, true, true, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarCreate::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgThread, OptionLong, m_constStrArgThread );
+ CMICMDBASE_GETOPTION( pArgFrame, OptionLong, m_constStrArgFrame );
+ CMICMDBASE_GETOPTION( pArgName, String, m_constStrArgName );
+ CMICMDBASE_GETOPTION( pArgFrameAddr, String, m_constStrArgFrameAddr );
+ CMICMDBASE_GETOPTION( pArgExpression, String, m_constStrArgExpression );
+
+ // Retrieve the --thread option's thread ID (only 1)
+ MIuint64 nThreadId = UINT64_MAX;
+ if( !pArgThread->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nThreadId ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str() ) );
+ return MIstatus::failure;
+ }
+ m_nThreadId = nThreadId;
+
+ // Retrieve the --frame option's number
+ MIuint64 nFrame = UINT64_MAX;
+ if( !pArgFrame->GetExpectedOption< CMICmdArgValNumber, MIuint64 >( nFrame ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_OPTION_NOT_FOUND ), m_cmdData.strMiCmd.c_str(), m_constStrArgFrame.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ const CMICmdArgValOptionLong::VecArgObjPtr_t & rVecFrameId( pArgFrame->GetExpectedOptions() );
+ CMICmdArgValOptionLong::VecArgObjPtr_t::const_iterator it2 = rVecFrameId.begin();
+ if( it2 != rVecFrameId.end() )
+ {
+ const CMICmdArgValNumber * pOption = static_cast< CMICmdArgValNumber * >( *it2 );
+ nFrame = pOption->GetValue();
+ }
+
+ bool bAutoName = false;
+ const CMIUtilString strArgName;
+ if( pArgName->GetFound() )
+ {
+ const CMIUtilString & rArg = pArgName->GetValue();
+ bAutoName = (rArg == "-");
+ }
+
+ const CMIUtilString & rStrExpression( pArgExpression->GetValue() );
+ m_strExpression = rStrExpression;
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ m_strVarName = "<unnamedvariable>";
+ if( bAutoName )
+ {
+ m_strVarName = CMIUtilString::Format( "var%u", CMICmnLLDBDebugSessionInfoVarObj::VarObjIdGet() );
+ CMICmnLLDBDebugSessionInfoVarObj::VarObjIdInc();
+ }
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+ lldb::SBThread thread = rProcess.GetThreadByIndexID( nThreadId );
+ lldb::SBFrame frame = thread.GetFrameAtIndex( nFrame );
+ lldb::SBValue value = frame.FindVariable( rStrExpression.c_str() );
+ if( !value.IsValid() )
+ value = frame.EvaluateExpression( rStrExpression.c_str() );
+ if( value.IsValid() )
+ {
+ m_bValid = true;
+ m_nChildren = value.GetNumChildren();
+ m_strType = CMICmnLLDBUtilSBValue( value ).GetTypeNameDisplay();
+
+ // This gets added to CMICmnLLDBDebugSessionInfoVarObj static container of varObjs
+ CMICmnLLDBDebugSessionInfoVarObj varObj( rStrExpression, m_strVarName, value );
+ m_strValue = varObj.GetValueFormatted();
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarCreate::Acknowledge( void )
+{
+ if( m_bValid )
+ {
+ // MI print "%s^done,name=\"%s\",numchild=\"%d\",value=\"%s\",type=\"%s\",thread-id=\"%llu\",has_more=\"%u\""
+ const CMICmnMIValueConst miValueConst( m_strVarName );
+ CMICmnMIValueResult miValueResultAll( "name", miValueConst );
+ const CMIUtilString strNumChild( CMIUtilString::Format( "%d", m_nChildren ) );
+ const CMICmnMIValueConst miValueConst2( strNumChild );
+ miValueResultAll.Add( "numchild", miValueConst2 );
+ const CMICmnMIValueConst miValueConst3( m_strValue );
+ miValueResultAll.Add( "value", miValueConst3 );
+ const CMICmnMIValueConst miValueConst4( m_strType );
+ miValueResultAll.Add( "type", miValueConst4 );
+ const CMIUtilString strThreadId( CMIUtilString::Format( "%llu", m_nThreadId ) );
+ const CMICmnMIValueConst miValueConst5( strThreadId );
+ miValueResultAll.Add( "thread-id", miValueConst5 );
+ const CMICmnMIValueConst miValueConst6( "0" );
+ miValueResultAll.Add( "has_more", miValueConst6 );
+
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResultAll );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+ }
+
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_VARIABLE_CREATION_FAILED ), m_strExpression.c_str() ) );
+ CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdVarCreate::CreateSelf( void )
+{
+ return new CMICmdCmdVarCreate();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarUpdate constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarUpdate::CMICmdCmdVarUpdate( void )
+: m_constStrArgPrintValues( "print-values" )
+, m_constStrArgName( "name" )
+, m_bValueChangedArrayType( false )
+, m_bValueChangedCompositeType( false )
+, m_bValueChangedNormalType( false )
+, m_miValueList( true )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "var-update";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdVarUpdate::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarUpdate destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarUpdate::~CMICmdCmdVarUpdate( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarUpdate::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgPrintValues, false, false ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgName, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarUpdate::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgName, String, m_constStrArgName );
+
+ const CMIUtilString & rVarObjName( pArgName->GetValue() );
+ CMICmnLLDBDebugSessionInfoVarObj varObj;
+ if( !CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( rVarObjName, varObj ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_VARIABLE_DOESNOTEXIST ), m_cmdData.strMiCmd.c_str(), rVarObjName.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ const CMIUtilString & rVarRealName( varObj.GetNameReal() ); MIunused( rVarRealName );
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( varObj.GetValue() );
+ const bool bValid = rValue.IsValid();
+ if( bValid && rValue.GetValueDidChange() )
+ {
+ m_bValueChangedNormalType = true;
+ varObj.UpdateValue();
+ m_strValueName = rVarObjName;
+ return MIstatus::success;
+ }
+
+ // Examine an array type variable
+ if( !ExamineSBValueForChange( varObj, false, m_bValueChangedArrayType ) )
+ return MIstatus::failure;
+
+ // Handle composite types i.e. struct or arrays
+ const MIuint nChildren = rValue.GetNumChildren();
+ for( MIuint i = 0; i < nChildren; i++ )
+ {
+ lldb::SBValue member = rValue.GetChildAtIndex( i );
+ if( !member.IsValid() )
+ continue;
+
+ const CMIUtilString varName( CMIUtilString::Format( "%s.%s", rVarObjName.c_str(), member.GetName() ) );
+ if( member.GetValueDidChange() )
+ {
+ // Handle composite
+ const CMIUtilString strValue( CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted( member, CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Natural ) );
+ const CMIUtilString strInScope( member.IsInScope() ? "true" : "false" );
+ MIFormResponse( varName, strValue, strInScope );
+
+ m_bValueChangedCompositeType = true;
+ }
+ else
+ {
+ // Handle array of composites
+ CMICmnLLDBDebugSessionInfoVarObj varObj;
+ if( CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( varName, varObj ) )
+ {
+ bool bValueChanged = false;
+ if( ExamineSBValueForChange( varObj, true, bValueChanged ) )
+ {
+ if( bValueChanged && CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( varName, varObj ) )
+ {
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( varObj.GetValue() );
+ const bool bValid = rValue.IsValid();
+ const CMIUtilString strValue( bValid ? varObj.GetValueFormatted() : "<unknown>" );
+ const CMIUtilString strInScope( (bValid && rValue.IsInScope()) ? "true" : "false" );
+ MIFormResponse( varName, strValue, strInScope );
+
+ m_bValueChangedCompositeType = true;
+ }
+ }
+ else
+ return MIstatus::failure;
+ }
+ }
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarUpdate::Acknowledge( void )
+{
+ if( m_bValueChangedArrayType || m_bValueChangedNormalType )
+ {
+ CMICmnLLDBDebugSessionInfoVarObj varObj;
+ CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( m_strValueName, varObj );
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( varObj.GetValue() );
+ const bool bValid = rValue.IsValid();
+ const CMIUtilString strValue( bValid ? varObj.GetValueFormatted() : "<unknown>" );
+ const CMIUtilString strInScope( (bValid && rValue.IsInScope()) ? "true" : "false" );
+
+ // MI print "%s^done,changelist=[{name=\"%s\",value=\"%s\",in_scope=\"%s\",type_changed=\"false\",has_more=\"0\"}]"
+ const CMICmnMIValueConst miValueConst( m_strValueName );
+ CMICmnMIValueResult miValueResult( "name", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ const CMICmnMIValueConst miValueConst2( strValue );
+ CMICmnMIValueResult miValueResult2( "value", miValueConst2 );
+ miValueTuple.Add( miValueResult2 );
+ const CMICmnMIValueConst miValueConst3( strInScope );
+ CMICmnMIValueResult miValueResult3( "in_scope", miValueConst3 );
+ miValueTuple.Add( miValueResult3 );
+ const CMICmnMIValueConst miValueConst4( "false" );
+ CMICmnMIValueResult miValueResult4( "type_changed", miValueConst4 );
+ miValueTuple.Add( miValueResult4 );
+ const CMICmnMIValueConst miValueConst5( "0" );
+ CMICmnMIValueResult miValueResult5( "has_more", miValueConst5 );
+ miValueTuple.Add( miValueResult5 );
+ const CMICmnMIValueList miValueList( miValueTuple );
+ CMICmnMIValueResult miValueResult6( "changelist", miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult6 );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+ }
+ else if( m_bValueChangedCompositeType )
+ {
+ // MI print "%s^done,changelist=[{name=\"%s\",value=\"%s\",in_scope=\"%s\",type_changed=\"false\",has_more=\"0\"},{name=\"%s\",value=\"%s\",in_scope=\"%s\",type_changed=\"false\",has_more=\"0\"}]"
+ CMICmnMIValueResult miValueResult6( "changelist", m_miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult6 );
+ m_miResultRecord = miRecordResult;
+ }
+ else
+ {
+ // MI: "%s^done,changelist=[]"
+ const CMICmnMIValueList miValueList( true );
+ CMICmnMIValueResult miValueResult6( "changelist", miValueList );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult6 );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdVarUpdate::CreateSelf( void )
+{
+ return new CMICmdCmdVarUpdate();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Form the MI response for multiple variables.
+// Type: Method.
+// Args: vrStrVarName - (R) Session var object's name.
+// vrStrValue - (R) Text version of the value held in the variable.
+// vrStrScope - (R) In scope "yes" or "no".
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarUpdate::MIFormResponse( const CMIUtilString & vrStrVarName, const CMIUtilString & vrStrValue, const CMIUtilString & vrStrScope )
+{
+ // MI print "[{name=\"%s\",value=\"%s\",in_scope=\"%s\",type_changed=\"false\",has_more=\"0\"}]"
+ const CMICmnMIValueConst miValueConst( vrStrVarName );
+ CMICmnMIValueResult miValueResult( "name", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ const CMICmnMIValueConst miValueConst2( vrStrValue );
+ CMICmnMIValueResult miValueResult2( "value", miValueConst2 );
+ bool bOk = miValueTuple.Add( miValueResult2 );
+ const CMICmnMIValueConst miValueConst3( vrStrScope );
+ CMICmnMIValueResult miValueResult3( "in_scope", miValueConst3 );
+ bOk = bOk && miValueTuple.Add( miValueResult3 );
+ const CMICmnMIValueConst miValueConst4( "false" );
+ CMICmnMIValueResult miValueResult4( "type_changed", miValueConst4 );
+ bOk = bOk && miValueTuple.Add( miValueResult4 );
+ const CMICmnMIValueConst miValueConst5( "0" );
+ CMICmnMIValueResult miValueResult5( "has_more", miValueConst5 );
+ bOk = bOk && miValueTuple.Add( miValueResult5 );
+ bOk = bOk && m_miValueList.Add( miValueTuple );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine if the var object is a array type variable. LLDB does not 'detect'
+// a value change for some types like elements in an array so have to re-evaluate
+// the expression again.
+// Type: Method.
+// Args: vrVarObj - (R) Session var object to examine.
+// vrwbChanged - (W) True = Is an array type and it changed,
+// False = Not an array type or not changed.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarUpdate::ExamineSBValueForChange( const CMICmnLLDBDebugSessionInfoVarObj & vrVarObj, const bool vbIgnoreVarType, bool & vrwbChanged )
+{
+ vrwbChanged = false;
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+ lldb::SBThread thread = rProcess.GetSelectedThread();
+ if( thread.GetNumFrames() == 0 )
+ {
+ return MIstatus::success;
+ }
+
+ const CMIUtilString & strVarObjParentName = vrVarObj.GetVarParentName();
+ lldb::SBFrame frame = thread.GetSelectedFrame();
+ const CMIUtilString & rExpression( vrVarObj.GetNameReal() );
+ CMIUtilString varExpression;
+ if( strVarObjParentName.empty() )
+ {
+ varExpression = rExpression;
+ }
+ else
+ {
+ CMICmnLLDBDebugSessionInfoVarObj varObjParent;
+ if( CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( strVarObjParentName, varObjParent ) )
+ varExpression = CMIUtilString::Format( "%s.%s", varObjParent.GetNameReal().c_str(), rExpression.c_str() );
+ else
+ {
+ // The parent is only assigned in the CMICmdCmdVarListChildren command, we have a problem, need to investigate
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_VARIABLE_DOESNOTEXIST ), m_cmdData.strMiCmd.c_str(), strVarObjParentName.c_str() ) );
+ return MIstatus::failure;
+ }
+ }
+
+ lldb::SBValue value = frame.EvaluateExpression( varExpression.c_str() );
+ if( !value.IsValid() )
+ value = frame.FindVariable( rExpression.c_str() );
+ if( value.IsValid() )
+ {
+ lldb::SBType valueType = value.GetType();
+ const lldb::BasicType eValueType = valueType.GetBasicType();
+ if( vbIgnoreVarType || (eValueType != lldb::BasicType::eBasicTypeInvalid) )
+ {
+ MIuint64 nPrevValue = 0;
+ MIuint64 nRevaluateValue = 0;
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( vrVarObj.GetValue() );
+ if( CMICmnLLDBProxySBValue::GetValueAsUnsigned( rValue, nPrevValue ) &&
+ CMICmnLLDBProxySBValue::GetValueAsUnsigned( value, nRevaluateValue ) &&
+ (nPrevValue != nRevaluateValue) )
+ {
+ // Have a value change so update the var object
+ vrwbChanged = true;
+ const CMICmnLLDBDebugSessionInfoVarObj varObj( rExpression, vrVarObj.GetName(), value, strVarObjParentName );
+ }
+ }
+ }
+
+ return MIstatus::success;
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarDelete constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarDelete::CMICmdCmdVarDelete( void )
+: m_constStrArgName( "name" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "var-delete";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdVarDelete::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarDelete::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgName, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarDelete destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarDelete::~CMICmdCmdVarDelete( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarDelete::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgName, String, m_constStrArgName );
+
+ const CMIUtilString & rVarObjName( pArgName->GetValue() );
+ CMICmnLLDBDebugSessionInfoVarObj::VarObjDelete( rVarObjName );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarDelete::Acknowledge( void )
+{
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdVarDelete::CreateSelf( void )
+{
+ return new CMICmdCmdVarDelete();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarAssign constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarAssign::CMICmdCmdVarAssign( void )
+: m_bOk( true )
+, m_constStrArgName( "name" )
+, m_constStrArgExpression( "expression" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "var-assign";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdVarAssign::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarAssign destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarAssign::~CMICmdCmdVarAssign( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarAssign::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgName, true, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgExpression, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarAssign::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgName, String, m_constStrArgName );
+ CMICMDBASE_GETOPTION( pArgExpression, String, m_constStrArgExpression );
+
+ const CMIUtilString & rVarObjName( pArgName->GetValue() );
+ const CMIUtilString & rExpression( pArgExpression->GetValue() );
+
+ CMICmnLLDBDebugSessionInfoVarObj varObj;
+ if( !CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( rVarObjName, varObj ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_VARIABLE_DOESNOTEXIST ), m_cmdData.strMiCmd.c_str(), rVarObjName.c_str() ) );
+ return MIstatus::failure;
+ }
+ m_varObjName = rVarObjName;
+
+ CMIUtilString strExpression( rExpression.Trim() );
+ strExpression = strExpression.Trim( '"' );
+ lldb::SBValue & rValue( const_cast< lldb::SBValue & >( varObj.GetValue() ) );
+ m_bOk = rValue.SetValueFromCString( strExpression.c_str() );
+ if( m_bOk )
+ varObj.UpdateValue();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarAssign::Acknowledge( void )
+{
+ if( m_bOk )
+ {
+ // MI print "%s^done,value=\"%s\""
+ CMICmnLLDBDebugSessionInfoVarObj varObj;
+ CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( m_varObjName, varObj );
+ const CMICmnMIValueConst miValueConst( varObj.GetValueFormatted() );
+ const CMICmnMIValueResult miValueResult( "value", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+ }
+
+ const CMICmnMIValueConst miValueConst( "expression could not be evaluated" );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdVarAssign::CreateSelf( void )
+{
+ return new CMICmdCmdVarAssign();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarSetFormat constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarSetFormat::CMICmdCmdVarSetFormat( void )
+: m_constStrArgName( "name" )
+, m_constStrArgFormatSpec( "format-spec" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "var-set-format";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdVarSetFormat::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarSetFormat destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarSetFormat::~CMICmdCmdVarSetFormat( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarSetFormat::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgName, true, true ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgFormatSpec, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarSetFormat::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgName, String, m_constStrArgName );
+ CMICMDBASE_GETOPTION( pArgFormatSpec, String, m_constStrArgFormatSpec );
+
+ const CMIUtilString & rVarObjName( pArgName->GetValue() );
+ const CMIUtilString & rExpression( pArgFormatSpec->GetValue() );
+
+ CMICmnLLDBDebugSessionInfoVarObj varObj;
+ if( !CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( rVarObjName, varObj ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_VARIABLE_DOESNOTEXIST ), m_cmdData.strMiCmd.c_str(), rVarObjName.c_str() ) );
+ return MIstatus::failure;
+ }
+ if( !varObj.SetVarFormat( CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForString( rExpression ) ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_VARIABLE_ENUM_INVALID ), m_cmdData.strMiCmd.c_str(), rVarObjName.c_str(), rExpression.c_str() ) );
+ return MIstatus::failure;
+ }
+ varObj.UpdateValue();
+
+ m_varObjName = rVarObjName;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarSetFormat::Acknowledge( void )
+{
+ // MI print "%s^done,changelist=[{name=\"%s\",value=\"%s\",in_scope=\"%s\",type_changed=\"false\",has_more=\"0\"}]"
+ CMICmnLLDBDebugSessionInfoVarObj varObj;
+ CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( m_varObjName, varObj );
+ const CMICmnMIValueConst miValueConst( m_varObjName );
+ const CMICmnMIValueResult miValueResult( "name", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ const CMICmnMIValueConst miValueConst2( varObj.GetValueFormatted() );
+ const CMICmnMIValueResult miValueResult2( "value", miValueConst2 );
+ miValueTuple.Add( miValueResult2 );
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( varObj.GetValue() );
+ const CMICmnMIValueConst miValueConst3( rValue.IsInScope() ? "true" : "false" );
+ const CMICmnMIValueResult miValueResult3( "in_scope", miValueConst3 );
+ miValueTuple.Add( miValueResult3 );
+ const CMICmnMIValueConst miValueConst4( "false" );
+ const CMICmnMIValueResult miValueResult4( "type_changed", miValueConst4 );
+ miValueTuple.Add( miValueResult4 );
+ const CMICmnMIValueConst miValueConst5( "0" );
+ const CMICmnMIValueResult miValueResult5( "type_changed", miValueConst5 );
+ miValueTuple.Add( miValueResult5 );
+ const CMICmnMIValueList miValueList( miValueTuple );
+ const CMICmnMIValueResult miValueResult6( "changelist", miValueList );
+
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult6 );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdVarSetFormat::CreateSelf( void )
+{
+ return new CMICmdCmdVarSetFormat();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarListChildren constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarListChildren::CMICmdCmdVarListChildren( void )
+: m_bValueValid( false )
+, m_nChildren( 0 )
+, m_constStrArgPrintValues( "print-values" )
+, m_constStrArgName( "name" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "var-list-children";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdVarListChildren::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarListChildren destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarListChildren::~CMICmdCmdVarListChildren( void )
+{
+ m_vecMiValueResult.clear();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarListChildren::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValNumber( m_constStrArgPrintValues, false, false ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgName, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarListChildren::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgName, String, m_constStrArgName );
+
+ const CMIUtilString & rVarObjName( pArgName->GetValue() );
+ CMICmnLLDBDebugSessionInfoVarObj varObj;
+ if( !CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( rVarObjName, varObj ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_VARIABLE_DOESNOTEXIST ), m_cmdData.strMiCmd.c_str(), rVarObjName.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( varObj.GetValue() );
+ m_bValueValid = rValue.IsValid();
+ if( !m_bValueValid )
+ return MIstatus::success;
+
+ m_vecMiValueResult.clear();
+ m_nChildren = rValue.GetNumChildren();
+ for( MIuint i = 0; i < m_nChildren; i++ )
+ {
+ lldb::SBValue member = rValue.GetChildAtIndex( i );
+ if( !member.IsValid() )
+ continue;
+ const CMICmnLLDBUtilSBValue utilValue( member );
+ const CMIUtilString strExp = utilValue.GetName();
+ const CMIUtilString name( CMIUtilString::Format( "%s.%s", rVarObjName.c_str(), strExp.c_str() ) );
+ const MIuint nChildren = member.GetNumChildren();
+ const CMIUtilString strThreadId( CMIUtilString::Format( "%u", member.GetThread().GetIndexID() ) );
+
+ // Varobj gets added to CMICmnLLDBDebugSessionInfoVarObj static container of varObjs
+ CMICmnLLDBDebugSessionInfoVarObj var( strExp, name, member, rVarObjName );
+
+ // MI print "child={name=\"%s\",exp=\"%s\",numchild=\"%d\",value=\"%s\",type=\"%s\",thread-id=\"%u\",has_more=\"%u\"}"
+ const CMICmnMIValueConst miValueConst( name );
+ const CMICmnMIValueResult miValueResult( "name", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ const CMICmnMIValueConst miValueConst2( strExp );
+ const CMICmnMIValueResult miValueResult2( "exp", miValueConst2 );
+ miValueTuple.Add( miValueResult2 );
+ const CMIUtilString strNumChild( CMIUtilString::Format( "%d", nChildren ) );
+ const CMICmnMIValueConst miValueConst3( strNumChild );
+ const CMICmnMIValueResult miValueResult3( "numchild", miValueConst3 );
+ miValueTuple.Add( miValueResult3 );
+ const CMICmnMIValueConst miValueConst5( utilValue.GetTypeNameDisplay() );
+ const CMICmnMIValueResult miValueResult5( "type", miValueConst5 );
+ miValueTuple.Add( miValueResult5 );
+ const CMICmnMIValueConst miValueConst6( strThreadId );
+ const CMICmnMIValueResult miValueResult6( "thread-id", miValueConst6 );
+ miValueTuple.Add( miValueResult6 );
+ const CMICmnMIValueConst miValueConst7( "0" );
+ const CMICmnMIValueResult miValueResult7( "has_more", miValueConst7 );
+ miValueTuple.Add( miValueResult7 );
+ const CMICmnMIValueResult miValueResult8( "child", miValueTuple );
+ m_vecMiValueResult.push_back( miValueResult8 );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarListChildren::Acknowledge( void )
+{
+ if( m_bValueValid )
+ {
+ // MI print "%s^done,numchild=\"%u\",children=[]""
+ const CMIUtilString strNumChild( CMIUtilString::Format( "%u", m_nChildren ) );
+ const CMICmnMIValueConst miValueConst( strNumChild );
+ CMICmnMIValueResult miValueResult( "numchild", miValueConst );
+
+ VecMIValueResult_t::const_iterator it = m_vecMiValueResult.begin();
+ if( it == m_vecMiValueResult.end() )
+ {
+ const CMICmnMIValueConst miValueConst( "[]" );
+ miValueResult.Add( "children", miValueConst );
+ }
+ else
+ {
+ CMICmnMIValueList miValueList( *it );
+ ++it;
+ while( it != m_vecMiValueResult.end() )
+ {
+ const CMICmnMIValueResult & rResult( *it );
+ miValueList.Add( rResult );
+
+ // Next
+ ++it;
+ }
+ miValueResult.Add( "children", miValueList );
+ }
+
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ // MI print "%s^done,numchild=\"0\""
+ const CMICmnMIValueConst miValueConst( "0" );
+ const CMICmnMIValueResult miValueResult( "numchild", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdVarListChildren::CreateSelf( void )
+{
+ return new CMICmdCmdVarListChildren();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarEvaluateExpression constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarEvaluateExpression::CMICmdCmdVarEvaluateExpression( void )
+: m_bValueValid( true )
+, m_constStrArgFormatSpec( "-f" )
+, m_constStrArgName( "name" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "var-evaluate-expression";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdVarEvaluateExpression::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarEvaluateExpression destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarEvaluateExpression::~CMICmdCmdVarEvaluateExpression( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarEvaluateExpression::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValOptionShort( m_constStrArgFormatSpec, false, false, CMICmdArgValListBase::eArgValType_String, 1 ) ) );
+ bOk = bOk && m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgName, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarEvaluateExpression::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgName, String, m_constStrArgName );
+
+ const CMIUtilString & rVarObjName( pArgName->GetValue() );
+ CMICmnLLDBDebugSessionInfoVarObj varObj;
+ if( !CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( rVarObjName, varObj ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_VARIABLE_DOESNOTEXIST ), m_cmdData.strMiCmd.c_str(), rVarObjName.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( varObj.GetValue() );
+ m_bValueValid = rValue.IsValid();
+ if( !m_bValueValid )
+ return MIstatus::success;
+
+ m_varObjName = rVarObjName;
+ varObj.UpdateValue();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarEvaluateExpression::Acknowledge( void )
+{
+ if( m_bValueValid )
+ {
+ CMICmnLLDBDebugSessionInfoVarObj varObj;
+ CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( m_varObjName, varObj );
+ const CMICmnMIValueConst miValueConst( varObj.GetValueFormatted() );
+ const CMICmnMIValueResult miValueResult( "value", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ const CMICmnMIValueConst miValueConst( "variable invalid" );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdVarEvaluateExpression::CreateSelf( void )
+{
+ return new CMICmdCmdVarEvaluateExpression();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarInfoPathExpression constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarInfoPathExpression::CMICmdCmdVarInfoPathExpression( void )
+: m_bValueValid( true )
+, m_constStrArgName( "name" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "var-info-path-expression";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdVarInfoPathExpression::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarInfoPathExpression destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarInfoPathExpression::~CMICmdCmdVarInfoPathExpression( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarInfoPathExpression::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgName, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarInfoPathExpression::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgName, String, m_constStrArgName );
+
+ const CMIUtilString & rVarObjName( pArgName->GetValue() );
+ CMICmnLLDBDebugSessionInfoVarObj varObj;
+ if( !CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( rVarObjName, varObj ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_VARIABLE_DOESNOTEXIST ), m_cmdData.strMiCmd.c_str(), rVarObjName.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( varObj.GetValue() );
+ m_bValueValid = rValue.IsValid();
+ if( !m_bValueValid )
+ return MIstatus::success;
+
+ lldb::SBStream stream;
+ if( !rValue.GetExpressionPath( stream, true ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_VARIABLE_EXPRESSIONPATH ), m_cmdData.strMiCmd.c_str(), rVarObjName.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ const MIchar * pPathExpression = stream.GetData();
+ if( pPathExpression == nullptr )
+ {
+ // Build expression from what we do know
+ m_strPathExpression = varObj.GetNameReal();
+ return MIstatus::success;
+ }
+
+ // Has LLDB returned a var signature of it's own
+ if( pPathExpression[ 0 ] != '$' )
+ {
+ m_strPathExpression = pPathExpression;
+ return MIstatus::success;
+ }
+
+ // Build expression from what we do know
+ const CMIUtilString & rVarParentName( varObj.GetVarParentName() );
+ if( rVarParentName.empty() )
+ {
+ m_strPathExpression = varObj.GetNameReal();
+ }
+ else
+ {
+ CMICmnLLDBDebugSessionInfoVarObj varObjParent;
+ if( !CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( rVarParentName, varObjParent ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_VARIABLE_DOESNOTEXIST ), m_cmdData.strMiCmd.c_str(), rVarParentName.c_str() ) );
+ return MIstatus::failure;
+ }
+ m_strPathExpression = CMIUtilString::Format( "%s.%s", varObjParent.GetNameReal().c_str(), varObj.GetNameReal().c_str() );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarInfoPathExpression::Acknowledge( void )
+{
+ if( m_bValueValid )
+ {
+ const CMICmnMIValueConst miValueConst( m_strPathExpression );
+ const CMICmnMIValueResult miValueResult( "path_expr", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+ return MIstatus::success;
+ }
+
+ const CMICmnMIValueConst miValueConst( "variable invalid" );
+ const CMICmnMIValueResult miValueResult( "msg", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdVarInfoPathExpression::CreateSelf( void )
+{
+ return new CMICmdCmdVarInfoPathExpression();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarShowAttributes constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarShowAttributes::CMICmdCmdVarShowAttributes( void )
+: m_constStrArgName( "name" )
+{
+ // Command factory matches this name with that received from the stdin stream
+ m_strMiCmd = "var-show-attributes";
+
+ // Required by the CMICmdFactory when registering *this command
+ m_pSelfCreatorFn = &CMICmdCmdVarShowAttributes::CreateSelf;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdCmdVarShowAttributes destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdCmdVarShowAttributes::~CMICmdCmdVarShowAttributes( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The parses the command line options
+// arguments to extract values for each of those arguments.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarShowAttributes::ParseArgs( void )
+{
+ bool bOk = m_setCmdArgs.Add( *(new CMICmdArgValString( m_constStrArgName, true, true ) ) );
+ return (bOk && ParseValidateCmdOptions() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command does work in this function.
+// The command is likely to communicate with the LLDB SBDebugger in here.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarShowAttributes::Execute( void )
+{
+ CMICMDBASE_GETOPTION( pArgName, String, m_constStrArgName );
+
+ const CMIUtilString & rVarObjName( pArgName->GetValue() );
+ CMICmnLLDBDebugSessionInfoVarObj varObj;
+ if( CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( rVarObjName, varObj ) )
+ {
+ SetError( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_VARIABLE_DOESNOTEXIST ), m_cmdData.strMiCmd.c_str(), rVarObjName.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The invoker requires this function. The command prepares a MI Record Result
+// for the work carried out in the Execute().
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdCmdVarShowAttributes::Acknowledge( void )
+{
+ // MI output: "%s^done,status=\"editable\"]"
+ const CMICmnMIValueConst miValueConst( "editable" );
+ const CMICmnMIValueResult miValueResult( "status", miValueConst );
+ const CMICmnMIResultRecord miRecordResult( m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult );
+ m_miResultRecord = miRecordResult;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdFactory when registering *this command. The factory
+// calls this function to create an instance of *this command.
+// Type: Static method.
+// Args: None.
+// Return: CMICmdBase * - Pointer to a new command.
+// Throws: None.
+//--
+CMICmdBase * CMICmdCmdVarShowAttributes::CreateSelf( void )
+{
+ return new CMICmdCmdVarShowAttributes();
+}
diff --git a/tools/lldb-mi/MICmdCmdVar.h b/tools/lldb-mi/MICmdCmdVar.h
new file mode 100644
index 000000000000..387cfc4ada83
--- /dev/null
+++ b/tools/lldb-mi/MICmdCmdVar.h
@@ -0,0 +1,382 @@
+//===-- MICmdCmdVar.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCmdVar.h
+//
+// Overview: CMICmdCmdVarCreate interface.
+// CMICmdCmdVarUpdate interface.
+// CMICmdCmdVarDelete interface.
+// CMICmdCmdVarAssign interface.
+// CMICmdCmdVarSetFormat interface.
+// CMICmdCmdVarListChildren interface.
+// CMICmdCmdVarEvaluateExpression interface.
+// CMICmdCmdVarInfoPathExpression interface.
+// CMICmdCmdVarShowAttributes interface.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery
+// command class as an example.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmdBase.h"
+#include "MICmnMIValueTuple.h"
+#include "MICmnMIValueList.h"
+#include "MICmnLLDBDebugSessionInfoVarObj.h"
+
+// Declarations:
+class CMICmnLLDBDebugSessionInfoVarObj;
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "var-create".
+// Gotchas: None.
+// Authors: Illya Rudkin 24/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdVarCreate : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdVarCreate( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdVarCreate( void );
+
+// Attribute:
+private:
+ CMIUtilString m_strVarName;
+ MIuint m_nChildren;
+ MIuint m_nMore;
+ MIuint64 m_nThreadId;
+ CMIUtilString m_strType;
+ bool m_bValid; // True = Variable is valid, false = not valid
+ CMIUtilString m_strExpression;
+ CMIUtilString m_strValue;
+ const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgThreadGroup; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgFrame; // Not specified in MI spec but Eclipse gives this option
+ const CMIUtilString m_constStrArgName;
+ const CMIUtilString m_constStrArgFrameAddr;
+ const CMIUtilString m_constStrArgExpression;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "var-update".
+// Gotchas: None.
+// Authors: Illya Rudkin 25/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdVarUpdate : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdVarUpdate( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdVarUpdate( void );
+
+// Methods:
+private:
+ bool ExamineSBValueForChange( const CMICmnLLDBDebugSessionInfoVarObj & vrVarObj, const bool vbIgnoreVarType, bool & vrwbChanged );
+ bool MIFormResponse( const CMIUtilString & vrStrVarName, const CMIUtilString & vrStrValue, const CMIUtilString & vrStrScope );
+
+// Attribute:
+private:
+ CMIUtilString m_strValueName;
+ const CMIUtilString m_constStrArgPrintValues; // Not handled by *this command
+ const CMIUtilString m_constStrArgName;
+ bool m_bValueChangedArrayType; // True = yes value changed, false = no change
+ bool m_bValueChangedCompositeType; // True = yes value changed, false = no change
+ bool m_bValueChangedNormalType; // True = yes value changed, false = no change
+ CMICmnMIValueList m_miValueList;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "var-delete".
+// Gotchas: None.
+// Authors: Illya Rudkin 25/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdVarDelete : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdVarDelete( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdVarDelete( void );
+
+// Attribute:
+private:
+ const CMIUtilString m_constStrArgName;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "var-assign".
+// Gotchas: None.
+// Authors: Illya Rudkin 25/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdVarAssign : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdVarAssign( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdVarAssign( void );
+
+// Attributes:
+private:
+ bool m_bOk; // True = success, false = failure
+ CMIUtilString m_varObjName;
+ const CMIUtilString m_constStrArgName;
+ const CMIUtilString m_constStrArgExpression;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "var-set-format".
+// Gotchas: None.
+// Authors: Illya Rudkin 26/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdVarSetFormat : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdVarSetFormat( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdVarSetFormat( void );
+
+// Attributes:
+private:
+ CMIUtilString m_varObjName;
+ const CMIUtilString m_constStrArgName;
+ const CMIUtilString m_constStrArgFormatSpec;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "var-list-children".
+// Gotchas: None.
+// Authors: Illya Rudkin 26/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdVarListChildren : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdVarListChildren( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdVarListChildren( void );
+
+// Typedefs:
+private:
+ typedef std::vector< CMICmnMIValueResult > VecMIValueResult_t;
+
+// Attributes:
+private:
+ bool m_bValueValid; // True = yes SBValue object is valid, false = not valid
+ VecMIValueResult_t m_vecMiValueResult;
+ MIuint m_nChildren;
+ const CMIUtilString m_constStrArgPrintValues; // Not handled by *this command
+ const CMIUtilString m_constStrArgName;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "var-evaluate-expression".
+// Gotchas: None.
+// Authors: Illya Rudkin 26/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdVarEvaluateExpression : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdVarEvaluateExpression( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdVarEvaluateExpression( void );
+
+// Attributes:
+private:
+ bool m_bValueValid; // True = yes SBValue object is valid, false = not valid
+ CMIUtilString m_varObjName;
+ const CMIUtilString m_constStrArgFormatSpec; // Not handled by *this command
+ const CMIUtilString m_constStrArgName;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "var-info-path-expression".
+// Gotchas: None.
+// Authors: Illya Rudkin 26/03/2014.
+// Changes: None.
+//--
+class CMICmdCmdVarInfoPathExpression : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdVarInfoPathExpression( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdVarInfoPathExpression( void );
+
+// Attributes:
+private:
+ bool m_bValueValid; // True = yes SBValue object is valid, false = not valid
+ CMIUtilString m_strPathExpression;
+ const CMIUtilString m_constStrArgName;
+};
+
+//++ ============================================================================
+// Details: MI command class. MI commands derived from the command base class.
+// *this class implements MI command "var-show-attributes".
+// Gotchas: None.
+// Authors: Illya Rudkin 19/05/2014.
+// Changes: None.
+//--
+class CMICmdCmdVarShowAttributes : public CMICmdBase
+{
+// Statics:
+public:
+ // Required by the CMICmdFactory when registering *this command
+ static CMICmdBase * CreateSelf( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmdCmdVarShowAttributes( void );
+
+// Overridden:
+public:
+ // From CMICmdInvoker::ICmd
+ virtual bool Execute( void );
+ virtual bool Acknowledge( void );
+ virtual bool ParseArgs( void );
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdCmdVarShowAttributes( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrArgName;
+};
+
diff --git a/tools/lldb-mi/MICmdCommands.cpp b/tools/lldb-mi/MICmdCommands.cpp
new file mode 100644
index 000000000000..4187b059b395
--- /dev/null
+++ b/tools/lldb-mi/MICmdCommands.cpp
@@ -0,0 +1,135 @@
+//===-- MICmdCommands.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCommands.cpp
+//
+// Overview: MI command are registered with the MI command factory.
+//
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdCommands.h"
+#include "MICmdFactory.h"
+#include "MICmdCmd.h"
+#include "MICmdCmdBreak.h"
+#include "MICmdCmdData.h"
+#include "MICmdCmdEnviro.h"
+#include "MICmdCmdExec.h"
+#include "MICmdCmdFile.h"
+#include "MICmdCmdGdbInfo.h"
+#include "MICmdCmdGdbSet.h"
+#include "MICmdCmdGdbThread.h"
+#include "MICmdCmdMiscellanous.h"
+#include "MICmdCmdStack.h"
+#include "MICmdCmdSupportInfo.h"
+#include "MICmdCmdSupportList.h"
+#include "MICmdCmdTarget.h"
+#include "MICmdCmdThread.h"
+#include "MICmdCmdTrace.h"
+#include "MICmdCmdVar.h"
+
+namespace MICmnCommands
+{
+ template< typename T >
+ static bool Register( void );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Command to command factory registration function.
+// Type: Template function.
+// Args: typename T - A command type class.
+// Return: bool - True = yes command is registered, false = command failed to register.
+// Throws: None.
+//--
+template< typename T >
+static bool MICmnCommands::Register( void )
+{
+ static CMICmdFactory & rCmdFactory = CMICmdFactory::Instance();
+ const CMIUtilString strMiCmd = T().GetMiCmd();
+ CMICmdFactory::CmdCreatorFnPtr fn = T().GetCmdCreatorFn();
+ return rCmdFactory.CmdRegister( strMiCmd, fn );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Register commands with MI command factory
+// Type: Function.
+// Args: None.
+// Return: bool - True = yes all commands are registered,
+// false = one or more commands failed to register.
+// Throws: None.
+//--
+bool MICmnCommands::RegisterAll( void )
+{
+ bool bOk = MIstatus::success;
+
+ bOk &= Register< CMICmdCmdSupportInfoMiCmdQuery >();
+ bOk &= Register< CMICmdCmdBreakAfter >();
+ bOk &= Register< CMICmdCmdBreakCondition >();
+ bOk &= Register< CMICmdCmdBreakDelete >();
+ bOk &= Register< CMICmdCmdBreakDisable >();
+ bOk &= Register< CMICmdCmdBreakEnable >();
+ bOk &= Register< CMICmdCmdBreakInsert >();
+ bOk &= Register< CMICmdCmdDataDisassemble >();
+ bOk &= Register< CMICmdCmdDataEvaluateExpression >();
+ bOk &= Register< CMICmdCmdDataReadMemoryBytes >();
+ bOk &= Register< CMICmdCmdDataReadMemory >();
+ bOk &= Register< CMICmdCmdDataListRegisterNames >();
+ bOk &= Register< CMICmdCmdDataListRegisterValues >();
+ bOk &= Register< CMICmdCmdDataWriteMemory >();
+ bOk &= Register< CMICmdCmdEnablePrettyPrinting >();
+ bOk &= Register< CMICmdCmdEnvironmentCd >();
+ bOk &= Register< CMICmdCmdExecContinue >();
+ bOk &= Register< CMICmdCmdExecInterrupt >();
+ bOk &= Register< CMICmdCmdExecFinish >();
+ bOk &= Register< CMICmdCmdExecNext >();
+ bOk &= Register< CMICmdCmdExecNextInstruction >();
+ bOk &= Register< CMICmdCmdExecRun >();
+ bOk &= Register< CMICmdCmdExecStep >();
+ bOk &= Register< CMICmdCmdExecStepInstruction >();
+ bOk &= Register< CMICmdCmdFileExecAndSymbols >();
+ bOk &= Register< CMICmdCmdGdbExit >();
+ bOk &= Register< CMICmdCmdGdbInfo >();
+ bOk &= Register< CMICmdCmdGdbSet >();
+ bOk &= Register< CMICmdCmdGdbThread >();
+ bOk &= Register< CMICmdCmdInferiorTtySet >();
+ bOk &= Register< CMICmdCmdInterpreterExec >();
+ bOk &= Register< CMICmdCmdListThreadGroups >();
+ bOk &= Register< CMICmdCmdSource >();
+ bOk &= Register< CMICmdCmdStackInfoDepth >();
+ bOk &= Register< CMICmdCmdStackListFrames >();
+ bOk &= Register< CMICmdCmdStackListArguments >();
+ bOk &= Register< CMICmdCmdStackListLocals >();
+ bOk &= Register< CMICmdCmdSupportListFeatures >();
+ bOk &= Register< CMICmdCmdTargetSelect >();
+ bOk &= Register< CMICmdCmdThreadInfo >();
+ bOk &= Register< CMICmdCmdVarAssign >();
+ bOk &= Register< CMICmdCmdVarCreate >();
+ bOk &= Register< CMICmdCmdVarDelete >();
+ bOk &= Register< CMICmdCmdVarEvaluateExpression >();
+ bOk &= Register< CMICmdCmdVarInfoPathExpression >();
+ bOk &= Register< CMICmdCmdVarListChildren >();
+ bOk &= Register< CMICmdCmdVarSetFormat >();
+ bOk &= Register< CMICmdCmdVarShowAttributes >();
+ bOk &= Register< CMICmdCmdVarUpdate >();
+
+ return bOk;
+}
diff --git a/tools/lldb-mi/MICmdCommands.h b/tools/lldb-mi/MICmdCommands.h
new file mode 100644
index 000000000000..7bfc8aef6867
--- /dev/null
+++ b/tools/lldb-mi/MICmdCommands.h
@@ -0,0 +1,36 @@
+//===-- MICmdCommands.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdCommands.h
+//
+// Overview: CMICmdCommands instantiated.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+namespace MICmnCommands
+{
+
+//++ ============================================================================
+// Details: MI Command are instantiated and registered automatically with the
+// Command Factory
+// Gotchas: None.
+// Authors: Illya Rudkin 18/02/2014.
+// Changes: None.
+//--
+bool RegisterAll( void );
+
+}
diff --git a/tools/lldb-mi/MICmdData.cpp b/tools/lldb-mi/MICmdData.cpp
new file mode 100644
index 000000000000..8eb84f32000a
--- /dev/null
+++ b/tools/lldb-mi/MICmdData.cpp
@@ -0,0 +1,24 @@
+//===-- MICmdData.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdData.cpp
+//
+// Overview: SMICmdData implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdData.h"
+
diff --git a/tools/lldb-mi/MICmdData.h b/tools/lldb-mi/MICmdData.h
new file mode 100644
index 000000000000..d54a21663581
--- /dev/null
+++ b/tools/lldb-mi/MICmdData.h
@@ -0,0 +1,74 @@
+//===-- MICmdData.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdData.h
+//
+// Overview: SMICmdData interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmnResources.h"
+
+//++ ============================================================================
+// Details: MI command metadata. Holds the command's name, MI number and options
+// as found on stdin. Holds the command's MI output (written to stdout).
+// Gotchas: None.
+// Authors: Illya Rudkin 18/02/2014.
+// Changes: None.
+//--
+struct SMICmdData
+{
+ SMICmdData( void )
+ : id( 0 )
+ , bCmdValid( false )
+ , bCmdExecutedSuccessfully( false )
+ , bMIOldStyle( false )
+ , bHasResultRecordExtra( false )
+ {
+ };
+
+ MIuint id; // A command's unique ID i.e. GUID
+ CMIUtilString strMiCmdToken; // The command's MI token (a number)
+ CMIUtilString strMiCmd; // The command's name
+ CMIUtilString strMiCmdOption; // The command's arguments or options
+ CMIUtilString strMiCmdAll; // The text as received from the client
+ CMIUtilString strMiCmdResultRecord; // Each command forms 1 response to its input
+ CMIUtilString strMiCmdResultRecordExtra; // Hack command produce more response text to help the client because of using LLDB
+ bool bCmdValid; // True = Valid MI format command, false = invalid
+ bool bCmdExecutedSuccessfully; // True = Command finished successfully, false = Did not start/did not complete
+ CMIUtilString strErrorDescription; // Command failed this is why
+ bool bMIOldStyle; // True = format "3thread", false = format "3-thread"
+ bool bHasResultRecordExtra; // True = Yes command produced additional MI output to its 1 line response, false = no extra MI output formed
+
+ void Clear( void )
+ {
+ id = 0;
+ strMiCmdToken.clear();
+ strMiCmd = MIRSRC( IDS_CMD_ERR_CMD_RUN_BUT_NO_ACTION );
+ strMiCmdOption.clear();
+ strMiCmdAll.clear();
+ strMiCmdResultRecord.clear();
+ strMiCmdResultRecordExtra.clear();
+ bCmdValid = false;
+ bCmdExecutedSuccessfully = false;
+ strErrorDescription.clear();
+ bMIOldStyle = false;
+ bHasResultRecordExtra = false;
+ }
+};
+
diff --git a/tools/lldb-mi/MICmdFactory.cpp b/tools/lldb-mi/MICmdFactory.cpp
new file mode 100644
index 000000000000..4897c60e4d66
--- /dev/null
+++ b/tools/lldb-mi/MICmdFactory.cpp
@@ -0,0 +1,229 @@
+//===-- MICmdFactory.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdFactory.cpp
+//
+// Overview: CMICmdFactory implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdFactory.h"
+#include "MICmnResources.h"
+#include "MICmdData.h"
+#include "MICmdBase.h"
+#include "MICmdCommands.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdFactory constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdFactory::CMICmdFactory( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdFactory destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdFactory::~CMICmdFactory( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this Command factory.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmdFactory::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = true;
+
+ MICmnCommands::RegisterAll();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this Command Factory.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmdFactory::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ m_mapMiCmdToCmdCreatorFn.clear();
+
+ m_bInitialized = false;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Register a command's creator function with the command identitier the MI
+// command name i.e. 'file-exec-and-symbols'.
+// Type: Method.
+// Args: vMiCmd - (R) Command's name, the MI command.
+// vCmdCreateFn - (R) Command's creator function pointer.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmdFactory::CmdRegister( const CMIUtilString & vMiCmd, CmdCreatorFnPtr vCmdCreateFn )
+{
+ if( !IsValid( vMiCmd ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CMDFACTORY_ERR_INVALID_CMD_NAME ), vMiCmd.c_str() ) );
+ return MIstatus::failure;
+ }
+ if( vCmdCreateFn == nullptr )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CMDFACTORY_ERR_INVALID_CMD_CR8FN ), vMiCmd.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ if( HaveAlready( vMiCmd ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CMDFACTORY_ERR_CMD_ALREADY_REGED ), vMiCmd.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ MapPairMiCmdToCmdCreatorFn_t pr( vMiCmd, vCmdCreateFn );
+ m_mapMiCmdToCmdCreatorFn.insert( pr );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Check a command is already registered.
+// Type: Method.
+// Args: vMiCmd - (R) Command's name, the MI command.
+// Return: True - registered.
+// False - not found.
+// Throws: None.
+//--
+bool CMICmdFactory::HaveAlready( const CMIUtilString & vMiCmd ) const
+{
+ const MapMiCmdToCmdCreatorFn_t::const_iterator it = m_mapMiCmdToCmdCreatorFn.find( vMiCmd );
+ if( it != m_mapMiCmdToCmdCreatorFn.end() )
+ return true;
+
+ return false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Check a command's name is valid:
+// - name is not empty
+// - name does not have spaces
+// Type: Method.
+// Args: vMiCmd - (R) Command's name, the MI command.
+// Return: True - valid.
+// False - not valid.
+// Throws: None.
+//--
+bool CMICmdFactory::IsValid( const CMIUtilString & vMiCmd ) const
+{
+ bool bValid = true;
+
+ if( vMiCmd.empty() )
+ {
+ bValid = false;
+ return false;
+ }
+
+ const MIint nPos = vMiCmd.find( " " );
+ if( nPos != (MIint) std::string::npos )
+ bValid = false;
+
+ return bValid;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Check a command is already registered.
+// Type: Method.
+// Args: vMiCmd - (R) Command's name, the MI command.
+// Return: True - registered.
+// False - not found.
+// Throws: None.
+//--
+bool CMICmdFactory::CmdExist( const CMIUtilString & vMiCmd ) const
+{
+ return HaveAlready( vMiCmd );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Create a command given the specified MI command name. The command data object
+// contains the options for the command.
+// Type: Method.
+// Args: vMiCmd - (R) Command's name, the MI command.
+// vCmdData - (RW) Command's metadata status/information/result object.
+// vpNewCmd - (W) New command instance.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmdFactory::CmdCreate( const CMIUtilString & vMiCmd, const SMICmdData & vCmdData, CMICmdBase *& vpNewCmd )
+{
+ bool bOk = MIstatus::success;
+
+ vpNewCmd = nullptr;
+
+ if( !IsValid( vMiCmd ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CMDFACTORY_ERR_INVALID_CMD_NAME ), vMiCmd.c_str() ) );
+ return MIstatus::failure;
+ }
+ if( !HaveAlready( vMiCmd ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CMDFACTORY_ERR_CMD_NOT_REGISTERED ), vMiCmd.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ const MapMiCmdToCmdCreatorFn_t::const_iterator it = m_mapMiCmdToCmdCreatorFn.find( vMiCmd );
+ const CMIUtilString & rMiCmd( (*it).first ); MIunused( rMiCmd );
+ CmdCreatorFnPtr pFn = (*it).second;
+ CMICmdBase * pCmd = (*pFn)();
+
+ SMICmdData cmdData( vCmdData );
+ cmdData.id = pCmd->GetGUID();
+ bOk = pCmd->SetCmdData( cmdData );
+ if( bOk )
+ vpNewCmd = pCmd;
+
+ return bOk;
+}
diff --git a/tools/lldb-mi/MICmdFactory.h b/tools/lldb-mi/MICmdFactory.h
new file mode 100644
index 000000000000..52281d1e7d1d
--- /dev/null
+++ b/tools/lldb-mi/MICmdFactory.h
@@ -0,0 +1,99 @@
+//===-- MICmdFactory.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdFactory.h
+//
+// Overview: CMICmdFactory interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers
+#include <map>
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MIUtilSingletonBase.h"
+
+// Declarations:
+class CMICmdBase;
+struct SMICmdData;
+
+//++ ============================================================================
+// Details: MI Command Factory. Holds a list of registered MI commands that
+// MI application understands to interpret. Creates commands objects.
+// The Command Factory is carried out in the main thread.
+// A singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 19/02/2014.
+// Changes: None.
+//--
+class CMICmdFactory
+: public CMICmnBase
+, public MI::ISingleton< CMICmdFactory >
+{
+ friend class MI::ISingleton< CMICmdFactory >;
+
+// Typedefs:
+public:
+ typedef CMICmdBase * (*CmdCreatorFnPtr)( void );
+
+// Class:
+public:
+ //++
+ // Description: Command's factory's interface for commands to implement.
+ //--
+ class ICmd
+ {
+ public:
+ virtual const CMIUtilString & GetMiCmd( void ) const = 0;
+ virtual CmdCreatorFnPtr GetCmdCreatorFn( void ) const = 0;
+ //virtual CMICmdBase * CreateSelf( void ) = 0; // Not possible as require a static creator function in the command class, here for awareness
+
+ /* dtor */ virtual ~ICmd( void ) {};
+ };
+
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+ bool CmdRegister( const CMIUtilString & vMiCmd, CmdCreatorFnPtr vCmdCreateFn );
+ bool CmdCreate( const CMIUtilString & vMiCmd, const SMICmdData & vCmdData, CMICmdBase *& vpNewCmd );
+ bool CmdExist( const CMIUtilString & vMiCmd ) const;
+
+// Methods:
+private:
+ /* ctor */ CMICmdFactory( void );
+ /* ctor */ CMICmdFactory( const CMICmdFactory & );
+ void operator=( const CMICmdFactory & );
+
+ bool HaveAlready( const CMIUtilString & vMiCmd ) const;
+ bool IsValid( const CMIUtilString & vMiCmd ) const;
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdFactory( void );
+
+// Typedefs:
+private:
+ typedef std::map< CMIUtilString, CmdCreatorFnPtr > MapMiCmdToCmdCreatorFn_t;
+ typedef std::pair< CMIUtilString, CmdCreatorFnPtr > MapPairMiCmdToCmdCreatorFn_t;
+
+// Attributes:
+private:
+ MapMiCmdToCmdCreatorFn_t m_mapMiCmdToCmdCreatorFn;
+};
diff --git a/tools/lldb-mi/MICmdInterpreter.cpp b/tools/lldb-mi/MICmdInterpreter.cpp
new file mode 100644
index 000000000000..dd5b2818705c
--- /dev/null
+++ b/tools/lldb-mi/MICmdInterpreter.cpp
@@ -0,0 +1,301 @@
+//===-- MICmdInterpreter.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdInterpreter.cpp
+//
+// Overview: CMICmdInterpreter implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdInterpreter.h"
+#include "MICmdFactory.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdInterpreter constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdInterpreter::CMICmdInterpreter( void )
+: m_rCmdFactory( CMICmdFactory::Instance() )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdInterpreter destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdInterpreter::~CMICmdInterpreter( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this Command Interpreter.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdInterpreter::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = true;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this Command Interpreter.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdInterpreter::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = false;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Establish whether the text data is an MI format type command.
+// Type: Method.
+// Args: vTextLine - (R) Text data to interpret.
+// vwbYesValid - (W) True = MI type command, false = not recognised.
+// vwbCmdNotInCmdFactor - (W) True = MI command not found in the command factory, false = recognised.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdInterpreter::ValidateIsMi( const CMIUtilString & vTextLine, bool & vwbYesValid, bool & vwbCmdNotInCmdFactor, SMICmdData & rwCmdData )
+{
+ vwbYesValid = false;
+ vwbCmdNotInCmdFactor = false;
+ rwCmdData.Clear();
+
+ if( vTextLine.empty() )
+ return MIstatus::success;
+
+ // MI format is [cmd #]-[command name]<space>[command arg(s)]
+ // i.e. 1-file-exec-and-symbols --thread-group i1 DEVICE_EXECUTABLE
+ // 5-data-evaluate-expression --thread 1 --frame 0 *(argv)
+
+ m_miCmdData.Clear();
+ m_miCmdData.strMiCmd = vTextLine;
+
+ // The following change m_miCmdData as valid parts are indentified
+ vwbYesValid = (MiHasCmdTokenEndingHypthen( vTextLine ) || MiHasCmdTokenEndingAlpha( vTextLine ));
+ vwbYesValid = vwbYesValid && MiHasCmd( vTextLine );
+ if( vwbYesValid )
+ {
+ vwbCmdNotInCmdFactor = !HasCmdFactoryGotMiCmd( MiGetCmdData() );
+ vwbYesValid = !vwbCmdNotInCmdFactor;
+ }
+
+ // Update command's meta data valid state
+ m_miCmdData.bCmdValid = vwbYesValid;
+
+ // Ok to return new updated command information
+ rwCmdData = MiGetCmdData();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Establish whether the command name entered on the stdin stream is recognised by
+// the MI driver.
+// Type: Method.
+// Args: vCmd - (R) Command information structure.
+// Return: bool - True = yes command is recognised, false = command not recognised.
+// Throws: None.
+//--
+bool CMICmdInterpreter::HasCmdFactoryGotMiCmd( const SMICmdData & vCmd ) const
+{
+ return m_rCmdFactory.CmdExist( vCmd.strMiCmd );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Does the command entered match the criteria for a MI command format.
+// The format to validate against is 'nn-' where there can be 1 to n digits.
+// I.e. '2-gdb-exit'.
+// Is the execution token present? The command token is entered into the
+// command meta data structure whether correct or not for reporting or later
+// command execution purposes.
+// Type: Method.
+// Args: vTextLine - (R) Text data to interpret.
+// Return: bool - True = yes command token present, false = command not recognised.
+// Throws: None.
+//--
+bool CMICmdInterpreter::MiHasCmdTokenEndingHypthen( const CMIUtilString & vTextLine )
+{
+ // The hythen is mandatory
+ const MIint nPos = vTextLine.find( "-", 0 );
+ if( (nPos == (MIint) std::string::npos) )
+ return false;
+
+ if( MiHasCmdTokenPresent( vTextLine ) )
+ {
+ const std::string strNum = vTextLine.substr( 0, nPos );
+ if( !CMIUtilString( strNum.c_str() ).IsNumber() )
+ return false;
+
+ m_miCmdData.strMiCmdToken = strNum.c_str();
+ }
+
+ m_miCmdData.bMIOldStyle = false;
+
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Does the command entered match the criteria for a MI command format.
+// The format to validate against is 'nnA' where there can be 1 to n digits.
+// 'A' represents any non numeric token. I.e. '1source .gdbinit'.
+// Is the execution token present? The command token is entered into the
+// command meta data structure whether correct or not for reporting or later
+// command execution purposes.
+// Type: Method.
+// Args: vTextLine - (R) Text data to interpret.
+// Return: bool - True = yes command token present, false = command not recognised.
+// Throws: None.
+//--
+bool CMICmdInterpreter::MiHasCmdTokenEndingAlpha( const CMIUtilString & vTextLine )
+{
+ MIchar cChar = vTextLine[ 0 ];
+ MIuint i = 0;
+ while( ::isdigit( cChar ) != 0 )
+ {
+ cChar = vTextLine[ ++i ];
+ }
+ if( ::isalpha( cChar ) == 0 )
+ return false;
+ if( i == 0 )
+ return false;
+
+ const std::string strNum = vTextLine.substr( 0, i );
+ m_miCmdData.strMiCmdToken = strNum.c_str();
+ m_miCmdData.bMIOldStyle = true;
+
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Does the command entered match the criteria for a MI command format.
+// Is the command token present before the hypen?
+// Type: Method.
+// Args: vTextLine - (R) Text data to interpret.
+// Return: bool - True = yes command token present, false = token not present.
+// Throws: None.
+//--
+bool CMICmdInterpreter::MiHasCmdTokenPresent( const CMIUtilString & vTextLine )
+{
+ const MIint nPos = vTextLine.find( "-", 0 );
+ return (nPos > 0);
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Does the command name entered match the criteria for a MI command format.
+// Is a recogised command present? The command name is entered into the
+// command meta data structure whether correct or not for reporting or later
+// command execution purposes. Command options is present are also put into the
+// command meta data structure.
+// Type: Method.
+// Args: vTextLine - (R) Command information structure.
+// Return: bool - True = yes command name present, false = command not recognised.
+// Throws: None.
+//--
+bool CMICmdInterpreter::MiHasCmd( const CMIUtilString & vTextLine )
+{
+ MIint nPos = 0;
+ if( m_miCmdData.bMIOldStyle )
+ {
+ char cChar = vTextLine[ 0 ];
+ MIuint i = 0;
+ while( ::isdigit( cChar ) != 0 )
+ {
+ cChar = vTextLine[ ++i ];
+ }
+ nPos = --i;
+ }
+ else
+ {
+ nPos = vTextLine.find( "-", 0 );
+ }
+
+ bool bFoundCmd = false;
+ const MIint nLen = vTextLine.length();
+ const MIint nPos2 = vTextLine.find( " ", nPos );
+ if( nPos2 != (MIint) std::string::npos )
+ {
+ if( nPos2 == nLen )
+ return false;
+ const CMIUtilString cmd = CMIUtilString( vTextLine.substr( nPos + 1, nPos2 - nPos - 1 ).c_str() );
+ if( cmd.empty() )
+ return false;
+
+ m_miCmdData.strMiCmd = cmd;
+
+ if( nPos2 < nLen )
+ m_miCmdData.strMiCmdOption = CMIUtilString( vTextLine.substr( nPos2 + 1, nLen - nPos2 - 1 ).c_str() );
+
+ bFoundCmd = true;
+ }
+ else
+ {
+ const CMIUtilString cmd = CMIUtilString( vTextLine.substr( nPos + 1, nLen - nPos - 1 ).c_str() );
+ if( cmd.empty() )
+ return false;
+ m_miCmdData.strMiCmd = cmd;
+ bFoundCmd = true;
+ }
+
+ if( bFoundCmd )
+ m_miCmdData.strMiCmdAll = vTextLine;
+
+ return bFoundCmd;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the just entered new command from stdin. It contains the command
+// name, number and any options.
+// Type: Method.
+// Args: vTextLine - (R) Command information structure.
+// Return: SMICmdData & - Command meta data information/result/status.
+// Throws: None.
+//--
+const SMICmdData & CMICmdInterpreter::MiGetCmdData( void ) const
+{
+ return m_miCmdData;
+}
+
diff --git a/tools/lldb-mi/MICmdInterpreter.h b/tools/lldb-mi/MICmdInterpreter.h
new file mode 100644
index 000000000000..d924a1f77af2
--- /dev/null
+++ b/tools/lldb-mi/MICmdInterpreter.h
@@ -0,0 +1,78 @@
+//===-- MICmdInterpreter.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdInterpreter.h
+//
+// Overview: CMICmdInterpreter interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MICmdData.h"
+#include "MIUtilSingletonBase.h"
+
+// Declarations:
+class CMICmdFactory;
+
+//++ ============================================================================
+// Details: MI command interpreter. It takes text data from the MI driver
+// (which got it from Stdin singleton) and validate the text to see if
+// matches Machine Interface (MI) format and commands defined in the
+// MI application.
+// A singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 18/02/2014.
+// Changes: None.
+//--
+class CMICmdInterpreter
+: public CMICmnBase
+, public MI::ISingleton< CMICmdInterpreter >
+{
+ friend MI::ISingleton< CMICmdInterpreter >;
+
+// Methods:
+public:
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+ bool ValidateIsMi( const CMIUtilString & vTextLine, bool & vwbYesValid, bool & vwbCmdNotInCmdFactor, SMICmdData & rwCmdData );
+
+// Methods:
+private:
+ /* ctor */ CMICmdInterpreter( void );
+ /* ctor */ CMICmdInterpreter( const CMICmdInterpreter & );
+ void operator=( const CMICmdInterpreter & );
+
+ bool HasCmdFactoryGotMiCmd( const SMICmdData & vCmdData ) const;
+ bool MiHasCmdTokenEndingHypthen( const CMIUtilString & vTextLine );
+ bool MiHasCmdTokenEndingAlpha( const CMIUtilString & vTextLine );
+ bool MiHasCmd( const CMIUtilString & vTextLine );
+ bool MiHasCmdTokenPresent( const CMIUtilString & vTextLine );
+ const SMICmdData & MiGetCmdData() const;
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdInterpreter( void );
+
+// Attributes:
+private:
+ SMICmdData m_miCmdData; // Filled in on each new line being interpreted
+ CMICmdFactory & m_rCmdFactory;
+};
diff --git a/tools/lldb-mi/MICmdInvoker.cpp b/tools/lldb-mi/MICmdInvoker.cpp
new file mode 100644
index 000000000000..41f9f77542a3
--- /dev/null
+++ b/tools/lldb-mi/MICmdInvoker.cpp
@@ -0,0 +1,333 @@
+//===-- MICmdInvoker.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdInvoker.cpp
+//
+// Overview: CMICmdInvoker implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdInvoker.h"
+#include "MICmdBase.h"
+#include "MICmdMgr.h"
+#include "MICmnLog.h"
+#include "MICmnStreamStdout.h"
+#include "MIDriver.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdInvoker constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdInvoker::CMICmdInvoker( void )
+: m_rStreamOut( CMICmnStreamStdout::Instance() )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdInvoker destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdInvoker::~CMICmdInvoker( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this Command Invoker.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdInvoker::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = true;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this Stdin stream.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdInvoker::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ CmdDeleteAll();
+
+ m_bInitialized = false;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Empty the map of invoked commands doing work. Command objects are deleted too.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMICmdInvoker::CmdDeleteAll( void )
+{
+ CMICmdMgr & rMgr = CMICmdMgr::Instance();
+ MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.begin();
+ while( it != m_mapCmdIdToCmd.end() )
+ {
+ const MIuint cmdId( (*it).first ); MIunused( cmdId );
+ CMICmdBase * pCmd = (*it).second;
+ const CMIUtilString & rCmdName( pCmd->GetCmdData().strMiCmd ); MIunused( rCmdName );
+ rMgr.CmdDelete( pCmd->GetCmdData() );
+
+ // Next
+ ++it;
+ }
+ m_mapCmdIdToCmd.clear();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Remove from the map of invoked commands doing work a command that has finished
+// its work. The command object is deleted too.
+// Type: Method.
+// Args: vId - (R) Command object's unique ID.
+// vbYesDeleteCmd - (R) True = Delete command object, false = delete via the Command Manager.
+// Return: None.
+// Throws: None.
+//--
+bool CMICmdInvoker::CmdDelete( const MIuint vId, const bool vbYesDeleteCmd /*= false*/ )
+{
+ CMICmdMgr & rMgr = CMICmdMgr::Instance();
+ MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find( vId );
+ if( it != m_mapCmdIdToCmd.end() )
+ {
+ CMICmdBase * pCmd = (*it).second;
+ if( vbYesDeleteCmd )
+ {
+ // Via registered interest command manager callback *this object to delete the command
+ m_mapCmdIdToCmd.erase( it );
+ delete pCmd;
+ }
+ else
+ // Notify other interested object of this command's pending deletion
+ rMgr.CmdDelete( pCmd->GetCmdData() );
+ }
+
+ if( m_mapCmdIdToCmd.empty() )
+ rMgr.CmdUnregisterForDeleteNotification( *this );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add to the map of invoked commands doing work a command that is about to
+// start to do work.
+// Type: Method.
+// Args: vCmd - (R) Command object.
+// Return: None.
+// Throws: None.
+//--
+bool CMICmdInvoker::CmdAdd( const CMICmdBase & vCmd )
+{
+ if( m_mapCmdIdToCmd.empty() )
+ {
+ CMICmdMgr & rMgr = CMICmdMgr::Instance();
+ rMgr.CmdRegisterForDeleteNotification( *this );
+ }
+
+ const MIuint & cmdId( vCmd.GetCmdData().id );
+ MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find( cmdId );
+ if( it != m_mapCmdIdToCmd.end() )
+ return MIstatus::success;
+
+ MapPairCmdIdToCmd_t pr( cmdId, const_cast< CMICmdBase *>( &vCmd ));
+ m_mapCmdIdToCmd.insert( pr );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Having previously had the potential command validated and found valid now
+// get the command executed.
+// If the Functionalityity returns MIstatus::failure call GetErrorDescription().
+// This function is used by the application's main thread.
+// Type: Method.
+// Args: vCmd - (RW) Command object.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmdInvoker::CmdExecute( CMICmdBase & vCmd )
+{
+ bool bOk = CmdAdd( vCmd );
+
+ if( bOk && !vCmd.ParseArgs() )
+ {
+ // Report command execution failed
+ const SMICmdData cmdData( vCmd.GetCmdData() );
+ CmdStdout( cmdData );
+ CmdCauseAppExit( vCmd );
+ CmdDelete( cmdData.id );
+
+ // Proceed to wait or execute next command
+ return MIstatus::success;
+ }
+
+ if( bOk && !vCmd.Execute() )
+ {
+ // Report command execution failed
+ const SMICmdData cmdData( vCmd.GetCmdData() );
+ CmdStdout( cmdData );
+ CmdCauseAppExit( vCmd );
+ CmdDelete( cmdData.id );
+
+ // Proceed to wait or execute next command
+ return MIstatus::success;
+ }
+
+ bOk = CmdExecuteFinished( vCmd );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Called when a command has finished its Execution() work either synchronously
+// because the command executed was the type a non event type or asynchronoulsy
+// via the command's callback (because of an SB Listener event). Needs to be called
+// so that *this invoker call do some house keeping and then proceed to call
+// the command's Acknowledge() function.
+// Type: Method.
+// Args: vCmd - (R) Command object.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmdInvoker::CmdExecuteFinished( CMICmdBase & vCmd )
+{
+ // Command finished now get the command to gather it's information and form the MI
+ // Result record
+ if( !vCmd.Acknowledge() )
+ {
+ // Report command acknowledge functionality failed
+ const SMICmdData cmdData( vCmd.GetCmdData() );
+ CmdStdout( cmdData );
+ CmdCauseAppExit( vCmd );
+ CmdDelete( cmdData.id );
+
+ // Proceed to wait or execute next command
+ return MIstatus::success;
+ }
+
+ // Retrieve the command's latest data/information. Needed for commands of the event type so have
+ // a record of commands pending finishing execution.
+ const CMIUtilString & rMIResultRecord( vCmd.GetMIResultRecord() );
+ SMICmdData cmdData( vCmd.GetCmdData() ); // Make a copy as the command will be deleted soon
+ cmdData.strMiCmdResultRecord = rMIResultRecord; // Precautionary copy as the command might forget to do this
+ if( vCmd.HasMIResultRecordExtra() )
+ {
+ cmdData.bHasResultRecordExtra = true;
+ const CMIUtilString & rMIExtra( vCmd.GetMIResultRecordExtra() );
+ cmdData.strMiCmdResultRecordExtra = rMIExtra; // Precautionary copy as the command might forget to do this
+ }
+
+ // Send command's MI response to the client
+ bool bOk = CmdStdout( cmdData );
+
+ // Delete the command object as do not require anymore
+ bOk = bOk && CmdDelete( vCmd.GetCmdData().id );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: If the MI Driver is not operating via a client i.e. Eclipse check the command
+// on failure suggests the application exits. A command can be such that a
+// failure cannot the allow the application to continue operating.
+// Args: vCmd - (R) Command object.
+// Return: None.
+// Return: None.
+// Throws: None.
+//--
+void CMICmdInvoker::CmdCauseAppExit( const CMICmdBase & vCmd ) const
+{
+ if( vCmd.GetExitAppOnCommandFailure() )
+ {
+ CMIDriver & rDriver( CMIDriver::Instance() );
+ if( rDriver.IsDriverDebuggingArgExecutable() )
+ {
+ rDriver.SetExitApplicationFlag( true );
+ }
+ }
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Write to stdout and the Log file the command's MI formatted result.
+// Type: vCmdData - (R) A command's information.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Return: None.
+// Throws: None.
+//--
+bool CMICmdInvoker::CmdStdout( const SMICmdData & vCmdData ) const
+{
+ bool bOk = m_pLog->WriteLog( vCmdData.strMiCmdAll );
+ const bool bLock = bOk && m_rStreamOut.Lock();
+ bOk = bOk && bLock && m_rStreamOut.WriteMIResponse( vCmdData.strMiCmdResultRecord );
+ if( bOk && vCmdData.bHasResultRecordExtra )
+ {
+ bOk = m_rStreamOut.WriteMIResponse( vCmdData.strMiCmdResultRecordExtra );
+ }
+ bOk = bLock && m_rStreamOut.Unlock();
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Required by the CMICmdMgr::ICmdDeleteCallback. *this object is registered
+// with the Command Manager to receive callbacks when a command is being deleted.
+// An object, *this invoker, does not delete a command object itself but calls
+// the Command Manager to delete a command object. This function is the Invoker's
+// called.
+// The Invoker owns the command objects and so can delete them but must do it
+// via the manager so other objects can be notified of the deletion.
+// Type: Method.
+// Args: vCmd - (RW) Command.
+// Return: None.
+// Throws: None.
+//--
+void CMICmdInvoker::Delete( SMICmdData & vCmd )
+{
+ CmdDelete( vCmd.id, true );
+}
diff --git a/tools/lldb-mi/MICmdInvoker.h b/tools/lldb-mi/MICmdInvoker.h
new file mode 100644
index 000000000000..b89d506b1f58
--- /dev/null
+++ b/tools/lldb-mi/MICmdInvoker.h
@@ -0,0 +1,118 @@
+//===-- MICmdInvoker.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdInvoker.h
+//
+// Overview: CMICmdInvoker interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers
+#include <map>
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MICmdData.h"
+#include "MICmdMgrSetCmdDeleteCallback.h"
+#include "MIUtilSingletonBase.h"
+
+// Declarations:
+class CMICmdBase;
+class CMICmnStreamStdout;
+
+//++ ============================================================================
+// Details: MI Command Invoker. The Invoker works on the command pattern design.
+// There two main jobs; action command Execute() function, followed by
+// the command's Acknowledge() function. When a command has finished its
+// execute function it returns to the invoker. The invoker then calls the
+// command's Acknowledge() function to do more work, form and give
+// back a MI result. In the meantime the Command Monitor is monitoring
+// the each command doing their Execute() function work so they do not
+// exceed a time limit which if it exceeds informs the command(s) to
+// stop work.
+// The work by the Invoker is carried out in the main thread.
+// The Invoker takes ownersip of any commands created which means it
+// is the only object to delete them when a command is finished working.
+// A singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 19/02/2014.
+// Changes: None.
+//--
+class CMICmdInvoker
+: public CMICmnBase
+, public CMICmdMgrSetCmdDeleteCallback::ICallback
+, public MI::ISingleton< CMICmdInvoker >
+{
+ friend class MI::ISingleton< CMICmdInvoker >;
+
+// Class:
+public:
+ //++
+ // Description: Invoker's interface for commands to implement.
+ //--
+ class ICmd
+ {
+ public:
+ virtual bool Acknowledge( void ) = 0;
+ virtual bool Execute( void ) = 0;
+ virtual bool ParseArgs( void ) = 0;
+ virtual bool SetCmdData( const SMICmdData & vCmdData ) = 0;
+ virtual const SMICmdData & GetCmdData( void ) const = 0;
+ virtual const CMIUtilString & GetErrorDescription( void ) const = 0;
+ virtual void CmdFinishedTellInvoker( void ) const = 0;
+ virtual const CMIUtilString & GetMIResultRecord( void ) const = 0;
+ virtual const CMIUtilString & GetMIResultRecordExtra( void ) const = 0;
+ virtual bool HasMIResultRecordExtra( void ) const = 0;
+
+ /* dtor */ virtual ~ICmd( void ) {};
+ };
+
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+ bool CmdExecute( CMICmdBase & vCmd );
+ bool CmdExecuteFinished( CMICmdBase & vCmd );
+
+// Typedefs:
+private:
+ typedef std::map< MIuint, CMICmdBase * > MapCmdIdToCmd_t;
+ typedef std::pair< MIuint, CMICmdBase * > MapPairCmdIdToCmd_t;
+
+// Methods:
+private:
+ /* ctor */ CMICmdInvoker( void );
+ /* ctor */ CMICmdInvoker( const CMICmdInvoker & );
+ void operator=( const CMICmdInvoker & );
+ void CmdDeleteAll( void );
+ bool CmdDelete( const MIuint vCmdId, const bool vbYesDeleteCmd = false );
+ bool CmdAdd( const CMICmdBase & vCmd );
+ bool CmdStdout( const SMICmdData & vCmdData ) const;
+ void CmdCauseAppExit( const CMICmdBase & vCmd ) const;
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdInvoker( void );
+ // From CMICmdMgrSetCmdDeleteCallback::ICallback
+ virtual void Delete( SMICmdData & vCmd );
+
+// Attributes:
+private:
+ MapCmdIdToCmd_t m_mapCmdIdToCmd;
+ CMICmnStreamStdout & m_rStreamOut;
+};
diff --git a/tools/lldb-mi/MICmdMgr.cpp b/tools/lldb-mi/MICmdMgr.cpp
new file mode 100644
index 000000000000..4abcbad3f48d
--- /dev/null
+++ b/tools/lldb-mi/MICmdMgr.cpp
@@ -0,0 +1,257 @@
+//===-- MICmdMgr.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdMgr.cpp
+//
+// Overview: CMICmdMgr implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdMgr.h"
+#include "MICmnResources.h"
+#include "MICmnLog.h"
+#include "MICmdInterpreter.h"
+#include "MICmdFactory.h"
+#include "MICmdInvoker.h"
+#include "MICmdBase.h"
+#include "MIUtilSingletonBase.h"
+#include "MIUtilSingletonHelper.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdMgr constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdMgr::CMICmdMgr( void )
+: m_interpretor( CMICmdInterpreter::Instance() )
+, m_factory( CMICmdFactory::Instance() )
+, m_invoker( CMICmdInvoker::Instance() )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmdMgr destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmdMgr::~CMICmdMgr( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this Command Manager.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmdMgr::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Note initialization order is important here as some resources depend on previous
+ MI::ModuleInit< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
+ MI::ModuleInit< CMICmnResources >( IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg );
+ if( bOk && !m_interpretor.Initialize() )
+ {
+ bOk = false;
+ errMsg = CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_CMDINTERPRETER ), m_interpretor.GetErrorDescription().c_str() );
+ }
+ if( bOk && !m_factory.Initialize() )
+ {
+ bOk = false;
+ errMsg = CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_CMDFACTORY ), m_factory.GetErrorDescription().c_str() );
+ }
+ if( bOk && !m_invoker.Initialize() )
+ {
+ bOk = false;
+ errMsg = CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_CMDINVOKER ), m_invoker.GetErrorDescription().c_str() );
+ }
+ m_bInitialized = bOk;
+
+ if( !bOk )
+ {
+ CMIUtilString strInitError( CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_CMDMGR ), errMsg.c_str() ) );
+ SetErrorDescription( strInitError );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this Command Manager.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmdMgr::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = false;
+
+ ClrErrorDescription();
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Tidy up
+ m_setCmdDeleteCallback.clear();
+
+ // Note shutdown order is important here
+ if( !m_invoker.Shutdown() )
+ {
+ bOk = false;
+ errMsg += CMIUtilString::Format( MIRSRC( IDS_MI_SHTDWN_ERR_CMDINVOKER ), m_invoker.GetErrorDescription().c_str() );
+ }
+ if( !m_factory.Shutdown() )
+ {
+ bOk = false;
+ if( !errMsg.empty() ) errMsg += ", ";
+ errMsg += CMIUtilString::Format( MIRSRC( IDS_MI_SHTDWN_ERR_CMDFACTORY ), m_factory.GetErrorDescription().c_str() );
+ }
+ if( !m_interpretor.Shutdown() )
+ {
+ bOk = false;
+ if( !errMsg.empty() ) errMsg += ", ";
+ errMsg += CMIUtilString::Format( MIRSRC( IDS_MI_SHTDWN_ERR_CMDINTERPRETER ), m_interpretor.GetErrorDescription().c_str() );
+ }
+ MI::ModuleShutdown< CMICmnResources >( IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg );
+ MI::ModuleShutdown< CMICmnLog >( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
+
+ if( !bOk )
+ {
+ SetErrorDescriptionn( MIRSRC( IDS_MI_SHUTDOWN_ERR ), errMsg.c_str() );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Establish whether the text data is an MI format type command.
+// Type: Method.
+// Args: vTextLine - (R) Text data to interpret.
+// vwbYesValid - (W) True = MI type command, false = not recognised.
+// vwbCmdNotInCmdFactor - (W) True = MI command not found in the command factor, false = recognised.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmdMgr::CmdInterpret( const CMIUtilString & vTextLine, bool & vwbYesValid, bool & vwbCmdNotInCmdFactor, SMICmdData & rwCmdData )
+{
+ return m_interpretor.ValidateIsMi( vTextLine, vwbYesValid, vwbCmdNotInCmdFactor, rwCmdData );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Having previously had the potential command validated and found valid now
+// get the command executed.
+// If the Functionalityity returns MIstatus::failure call GetErrorDescription().
+// This function is used by the application's main thread.
+// Type: Method.
+// Args: vCmdData - (RW) Command meta data.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmdMgr::CmdExecute( const SMICmdData & vCmdData )
+{
+ bool bOk = MIstatus::success;
+
+ // Pass the command's meta data structure to the command
+ // so it can update it if required. (Need to copy it out of the
+ // command before the command is deleted)
+ CMICmdBase * pCmd = nullptr;
+ bOk = m_factory.CmdCreate( vCmdData.strMiCmd, vCmdData, pCmd );
+ if( !bOk )
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_CMDMGR_ERR_CMD_FAILED_CREATE ), m_factory.GetErrorDescription().c_str() ) );
+ SetErrorDescription( errMsg );
+ return MIstatus::failure;
+ }
+
+ bOk = m_invoker.CmdExecute( *pCmd );
+ if( !bOk )
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_CMDMGR_ERR_CMD_INVOKER ), m_invoker.GetErrorDescription().c_str() ) );
+ SetErrorDescription( errMsg );
+ return MIstatus::failure;
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Iterate all interested clients and tell them a command is being deleted.
+// Type: Method.
+// Args: vCmdData - (RW) The command to be deleted.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdMgr::CmdDelete( SMICmdData vCmdData )
+{
+ // Note vCmdData is a copy! The command holding its copy will be deleted soon
+ // we still need to iterate callback clients after a command object is deleted
+
+ m_setCmdDeleteCallback.Delete( vCmdData );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Register an object to be called when a command object is deleted.
+// Type: Method.
+// Args: vObject - (R) A new interested client.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdMgr::CmdRegisterForDeleteNotification( CMICmdMgrSetCmdDeleteCallback::ICallback & vObject )
+{
+ return m_setCmdDeleteCallback.Register( vObject );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Unregister an object from being called when a command object is deleted.
+// Type: Method.
+// Args: vObject - (R) The was interested client.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmdMgr::CmdUnregisterForDeleteNotification( CMICmdMgrSetCmdDeleteCallback::ICallback & vObject )
+{
+ return m_setCmdDeleteCallback.Unregister( vObject );
+}
diff --git a/tools/lldb-mi/MICmdMgr.h b/tools/lldb-mi/MICmdMgr.h
new file mode 100644
index 000000000000..2b6a99248b16
--- /dev/null
+++ b/tools/lldb-mi/MICmdMgr.h
@@ -0,0 +1,83 @@
+//===-- MICmdMgr.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdMgr.h
+//
+// Overview: CMICmdMgr interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers
+#include <set>
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MICmdBase.h"
+#include "MICmdMgrSetCmdDeleteCallback.h"
+#include "MIUtilSingletonBase.h"
+
+// Declarations:
+class CMICmdInterpreter;
+class CMICmdFactory;
+class CMICmdInvoker;
+class CMICmdBase;
+
+//++ ============================================================================
+// Details: MI command manager. Oversees command operations, controls command
+// production and the running of commands.
+// Command Invoker, Command Factory and Command Monitor while independant
+// units are overseen/managed by *this manager.
+// A singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 19/02/2014.
+// Changes: None.
+//--
+class CMICmdMgr
+: public CMICmnBase
+, public MI::ISingleton< CMICmdMgr >
+{
+ friend class MI::ISingleton< CMICmdMgr >;
+
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+
+ bool CmdInterpret( const CMIUtilString & vTextLine, bool & vwbYesValid, bool & vwbCmdNotInCmdFactor, SMICmdData & rwCmdData );
+ bool CmdExecute( const SMICmdData & vCmdData );
+ bool CmdDelete( SMICmdData vCmdData );
+ bool CmdRegisterForDeleteNotification( CMICmdMgrSetCmdDeleteCallback::ICallback & vObject );
+ bool CmdUnregisterForDeleteNotification( CMICmdMgrSetCmdDeleteCallback::ICallback & vObject );
+
+// Methods:
+private:
+ /* ctor */ CMICmdMgr( void );
+ /* ctor */ CMICmdMgr( const CMICmdMgr & );
+ void operator=( const CMICmdMgr & );
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmdMgr( void );
+
+// Attributes:
+private:
+ CMICmdInterpreter & m_interpretor;
+ CMICmdFactory & m_factory;
+ CMICmdInvoker & m_invoker;
+ CMICmdMgrSetCmdDeleteCallback::CSetClients m_setCmdDeleteCallback;
+}; \ No newline at end of file
diff --git a/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.cpp b/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.cpp
new file mode 100644
index 000000000000..1303a8832f66
--- /dev/null
+++ b/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.cpp
@@ -0,0 +1,110 @@
+//===-- MICmdMgrSetCmdDeleteCallback.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdMgrSetCmdDeleteCallback.cpp
+//
+// Overview: CSetClients implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmdMgrSetCmdDeleteCallback.h"
+
+namespace CMICmdMgrSetCmdDeleteCallback
+{
+
+//++ ------------------------------------------------------------------------------------
+// Details: CSetClients constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CSetClients::CSetClients( void )
+: m_bClientUnregistered( false )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CSetClients destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CSetClients::~CSetClients( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Register an object to be called when a command object is deleted.
+// Type: Method.
+// Args: vObject - (R) A new interested client.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CSetClients::Register( ICallback & vObject )
+{
+ insert( &vObject );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Unregister an object from being called when a command object is deleted.
+// Type: Method.
+// Args: vObject - (R) The was interested client.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CSetClients::Unregister( ICallback & vObject )
+{
+ m_bClientUnregistered = true;
+ erase( &vObject );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Iterate all interested clients and tell them a command is being deleted.
+// Type: Method.
+// Args: vCmd - (RW) The command to be deleted.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+void CSetClients::Delete( SMICmdData & vCmd )
+{
+ m_bClientUnregistered = false; // Reset
+ iterator it = begin();
+ while( it != end() )
+ {
+ ICallback * pObj = *it;
+ pObj->Delete( vCmd );
+
+ if( m_bClientUnregistered )
+ {
+ m_bClientUnregistered = false; // Reset
+ it = begin();
+ }
+ else
+ // Next
+ ++it;
+ }
+}
+
+} // namespace CMICmdMgrSetCmdDeleteCallback
diff --git a/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.h b/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.h
new file mode 100644
index 000000000000..3579d3582615
--- /dev/null
+++ b/tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.h
@@ -0,0 +1,88 @@
+//===-- MICmdMgrSetCmdDeleteCallback.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmdMgrSetCmdDeleteCallback.h
+//
+// Overview: ICallback interface.
+// CSetClients interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <set>
+
+// In-house headers:
+#include "MICmnBase.h"
+
+// Declarations:
+struct SMICmdData;
+
+namespace CMICmdMgrSetCmdDeleteCallback
+{
+
+//++ ============================================================================
+// Details: MI Command Manager interface for client call back.
+// Objects that want to be notified of a command being deleted
+// inherit this interface and register interest in command object
+// deletion. An object deleting a command must not do it itself but call
+// the Command Manager CmdDelete() function to delete a command object.
+// Gotchas: None.
+// Authors: Illya Rudkin 21/02/2014.
+// Changes: None.
+//--
+class ICallback
+{
+public:
+ virtual void Delete( SMICmdData & vCmd ) = 0;
+
+ /* dtor */ virtual ~ICallback( void ) {};
+};
+
+//++ ============================================================================
+// Details: MI Command Manager container for clients registered interest in command
+// objects being deleted. Objects register an interest so when a command
+// is to be deleted that object wanting the delete calls the Command
+// Manager to delete the command object. In so do all other registered
+// objects get called to about the deletion including the object wanting
+// to do the delete in the first place.
+// Gotchas: None.
+// Authors: Illya Rudkin 21/02/2014.
+// Changes: None.
+//--
+class CSetClients
+: public std::set< class ICallback * >
+, public CMICmnBase
+{
+// Methods:
+public:
+ /* ctor */ CSetClients( void );
+
+ bool Register( class ICallback & vObject );
+ bool Unregister( class ICallback & vObject );
+ void Delete( SMICmdData & vCmdData );
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CSetClients( void );
+
+// Attributes:
+private:
+ bool m_bClientUnregistered; // True = yes while deleting a client unregistered, false = no client unregistered during deletion
+};
+
+} // namespace CMICmdMgrSetCmdDeleteCallback
diff --git a/tools/lldb-mi/MICmnBase.cpp b/tools/lldb-mi/MICmnBase.cpp
new file mode 100644
index 000000000000..3da7a41b3336
--- /dev/null
+++ b/tools/lldb-mi/MICmnBase.cpp
@@ -0,0 +1,144 @@
+//===-- MICmnBase.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnBase.cpp
+//
+// Overview: CMICmnBase implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third party headers
+#include <stdarg.h> // va_list, va_start, var_end
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MICmnLog.h"
+#include "MICmnStreamStderr.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnBase constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnBase::CMICmnBase( void )
+: m_strMILastErrorDescription( CMIUtilString() )
+, m_bInitialized( false )
+, m_pLog( &CMICmnLog::Instance() )
+, m_clientUsageRefCnt( 0 )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnBase destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnBase::~CMICmnBase( void )
+{
+ m_pLog = NULL;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve whether *this object has an error description set.
+// Type: Method.
+// Args: None.
+// Return: bool - True = Yes already defined, false = empty discription.
+// Throws: None.
+//--
+bool CMICmnBase::HaveErrorDescription( void ) const
+{
+ return m_strMILastErrorDescription.empty();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve MI's last error condition.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - Text description.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnBase::GetErrorDescription( void ) const
+{
+ return m_strMILastErrorDescription;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set MI's error condition description. This may be accessed by clients and
+// seen by users. Message is available to the client using the server and sent
+// to the Logger.
+// Type: Method.
+// Args: vrTxt - (R) Text description.
+// Return: None.
+// Throws: None.
+//--
+void CMICmnBase::SetErrorDescription( const CMIUtilString & vrTxt ) const
+{
+ m_strMILastErrorDescription = vrTxt;
+ if( !vrTxt.empty() )
+ {
+ const CMIUtilString txt( CMIUtilString::Format( "Error: %s", vrTxt.c_str() ) );
+ CMICmnStreamStderr::Instance().Write( txt );
+ }
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set MI's error condition description. This may be accessed by clients and
+// seen by users. Message is available to the client using the server and sent
+// to the Logger.
+// Type: Method.
+// Args: vrTxt - (R) Text description.
+// Return: None.
+// Throws: None.
+//--
+void CMICmnBase::SetErrorDescriptionNoLog( const CMIUtilString & vrTxt ) const
+{
+ m_strMILastErrorDescription = vrTxt;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Clear MI's error condition description.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMICmnBase::ClrErrorDescription( void ) const
+{
+ m_strMILastErrorDescription.clear();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set MI's error condition description. This may be accessed by clients and
+// seen by users. Message is available to the client using the server and sent
+// to the Logger.
+// Type: Method.
+// Args: vrFormat - (R) Format string.
+// ... - (R) Variable number of CMIUtilString type objects.
+// Return: None.
+// Throws: None.
+//--
+void CMICmnBase::SetErrorDescriptionn( const CMIUtilString & vrFormat, ... ) const
+{
+ va_list args;
+ va_start( args, vrFormat );
+ CMIUtilString strResult = CMIUtilString::FormatValist( vrFormat, args );
+ va_end( args );
+
+ SetErrorDescription( strResult );
+} \ No newline at end of file
diff --git a/tools/lldb-mi/MICmnBase.h b/tools/lldb-mi/MICmnBase.h
new file mode 100644
index 000000000000..db7338c5581f
--- /dev/null
+++ b/tools/lldb-mi/MICmnBase.h
@@ -0,0 +1,60 @@
+//===-- MICmnBase.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnBase.h
+//
+// Overview: CMICmnBase interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MIDataTypes.h"
+#include "MIUtilString.h"
+
+// Declarations:
+class CMICmnLog;
+
+//++ ============================================================================
+// Details: MI common code implementation base class.
+// Gotchas: None.
+// Authors: Illya Rudkin 28/01/2014.
+// Changes: None.
+//--
+class CMICmnBase
+{
+// Methods:
+public:
+ /* ctor */ CMICmnBase( void );
+
+ bool HaveErrorDescription( void ) const;
+ const CMIUtilString & GetErrorDescription( void ) const;
+ void SetErrorDescription( const CMIUtilString & vrTxt ) const;
+ void SetErrorDescriptionn( const CMIUtilString & vrFormat, ... ) const;
+ void SetErrorDescriptionNoLog( const CMIUtilString & vrTxt ) const;
+ void ClrErrorDescription( void ) const;
+
+// Overrideable:
+public:
+ /* dtor */ virtual ~CMICmnBase( void );
+
+// Attributes:
+protected:
+ mutable CMIUtilString m_strMILastErrorDescription;
+ bool m_bInitialized; // True = yes successfully initialized, false = no yet or failed
+ CMICmnLog * m_pLog; // Allow all derived classes to use the logger
+ MIint m_clientUsageRefCnt; // Count of client using *this object so not shutdown() object to early
+}; \ No newline at end of file
diff --git a/tools/lldb-mi/MICmnConfig.h b/tools/lldb-mi/MICmnConfig.h
new file mode 100644
index 000000000000..68093e87998b
--- /dev/null
+++ b/tools/lldb-mi/MICmnConfig.h
@@ -0,0 +1,50 @@
+//===-- MICmnConfig.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnConfig.h
+//
+// Overview: Common defines to guide feature inclusion at compile time.
+//
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+#pragma once
+
+// 1 = Yes compile MI Driver version, 0 = compile original LLDB driver code only.
+// 0 was mainly just for testing purposes and so may be removed at a later time.
+#define MICONFIG_COMPILE_MIDRIVER_VERSION 1
+
+// 1 = Show debug process attach modal dialog, 0 = do not show
+// For windows only ATM, other OS's code is an infinite loop which a debugger must change a value to continue
+#define MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG 0
+
+// 1 = Compile in and init LLDB driver code alongside MI version, 0 = do not compile in
+#define MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER 1
+
+// 1 = Give runtime our own custom buffer, 0 = Use runtime managed buffer
+#define MICONFIG_CREATE_OWN_STDIN_BUFFER 0
+
+// 1 = Use the MI driver regardless of --interpreter, 0 = require --interpreter argument
+// This depends on MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
+#define MICONFIG_DEFAULT_TO_MI_DRIVER 0
+
+// 1 = Check for stdin before we issue blocking read, 0 = issue blocking call always
+#define MICONFIG_POLL_FOR_STD_IN 1
+
+// 1 = Write to MI's Log file warnings about commands that did not handle arguments or
+// options present to them by the driver's client, 0 = no warnings given
+#define MICONFIG_GIVE_WARNING_CMD_ARGS_NOT_HANDLED 1
+
+// 1 = Enable MI Driver in MI mode to create a local debug session, 0 = Report "Not implemented"
+#define MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION 0 \ No newline at end of file
diff --git a/tools/lldb-mi/MICmnLLDBBroadcaster.cpp b/tools/lldb-mi/MICmnLLDBBroadcaster.cpp
new file mode 100644
index 000000000000..743100ae7b0f
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBBroadcaster.cpp
@@ -0,0 +1,89 @@
+//===-- MICmnLLDBBroadcaster.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBBroadcaster.cpp
+//
+// Overview: CMICmnLLDBBroadcaster implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnLLDBBroadcaster.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBBroadcaster constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBBroadcaster::CMICmnLLDBBroadcaster( void )
+: lldb::SBBroadcaster( "MI driver" )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBBroadcaster destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBBroadcaster::~CMICmnLLDBBroadcaster( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this broardcaster object.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBBroadcaster::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = MIstatus::success;
+
+ return m_bInitialized;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this broardcaster object.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBBroadcaster::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = false;
+
+ return MIstatus::success;
+}
+
diff --git a/tools/lldb-mi/MICmnLLDBBroadcaster.h b/tools/lldb-mi/MICmnLLDBBroadcaster.h
new file mode 100644
index 000000000000..6c3300aefcc4
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBBroadcaster.h
@@ -0,0 +1,61 @@
+//===-- MICmnLLDBBroadcaster.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBBroadcaster.h
+//
+// Overview: CMICmnLLDBBroadcaster interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include <lldb/API/SBBroadcaster.h>
+#include "MICmnBase.h"
+#include "MIUtilSingletonBase.h"
+
+//++ ============================================================================
+// Details: MI derived class from LLDB SBBroardcaster API.
+//
+// *** This class (files) is a place holder until we know we need it or
+// *** not
+//
+// A singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 28/02/2014.
+// Changes: None.
+//--
+class CMICmnLLDBBroadcaster
+: public CMICmnBase
+, public lldb::SBBroadcaster
+, public MI::ISingleton< CMICmnLLDBBroadcaster >
+{
+ friend MI::ISingleton< CMICmnLLDBBroadcaster >;
+
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+// Methods:
+private:
+ /* ctor */ CMICmnLLDBBroadcaster( void );
+ /* ctor */ CMICmnLLDBBroadcaster( const CMICmnLLDBBroadcaster & );
+ void operator=( const CMICmnLLDBBroadcaster & );
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnLLDBBroadcaster( void );
+};
diff --git a/tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp b/tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp
new file mode 100644
index 000000000000..3b7789ee1d63
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp
@@ -0,0 +1,1312 @@
+//===-- MICmnLLDBDebugSessionInfo.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBDebugSessionInfo.cpp
+//
+// Overview: CMICmnLLDBDebugSessionInfo implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third party headers:
+#include <lldb/API/SBThread.h>
+#ifdef _WIN32
+ #include <io.h> // For the ::_access()
+#else
+ #include <unistd.h> // For the ::access()
+#endif // _WIN32
+#include <lldb/API/SBBreakpointLocation.h>
+
+// In-house headers:
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MICmnLLDBDebugger.h"
+#include "MICmnResources.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnMIValueList.h"
+#include "MICmnMIValueTuple.h"
+#include "MICmdData.h"
+#include "MICmnLLDBUtilSBValue.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebugSessionInfo constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfo::CMICmnLLDBDebugSessionInfo( void )
+: m_rLldbDebugger( CMICmnLLDBDebugger::Instance().GetTheDebugger() )
+, m_rLlldbListener( CMICmnLLDBDebugger::Instance().GetTheListener() )
+, m_nBrkPointCntMax( INT32_MAX )
+, m_currentSelectedThread( LLDB_INVALID_THREAD_ID )
+, m_constStrSharedDataKeyWkDir( "Working Directory" )
+, m_constStrSharedDataSolibPath( "Solib Path" )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebugSessionInfo destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfo::~CMICmnLLDBDebugSessionInfo( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this object.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ m_currentSelectedThread = LLDB_INVALID_THREAD_ID;
+ CMICmnLLDBDebugSessionInfoVarObj::VarObjIdResetToZero();
+
+ m_bInitialized = MIstatus::success;
+
+ return m_bInitialized;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this object.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Tidy up
+ bOk = SharedDataDestroy();
+ if( !bOk )
+ {
+ errMsg = CMIUtilString::Format( MIRSRC( IDS_DBGSESSION_ERR_SHARED_DATA_RELEASE ) );
+ errMsg += "\n";
+ }
+ m_vecActiveThreadId.clear();
+ CMICmnLLDBDebugSessionInfoVarObj::VarObjClear();
+
+ m_bInitialized = false;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Command instances can create and share data between other instances of commands.
+// Data can also be assigned by a command and retrieved by LLDB event handler.
+// This function takes down those resources build up over the use of the commands.
+// This function should be called when the creation and running of command has
+// stopped i.e. application shutdown.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::SharedDataDestroy( void )
+{
+ m_mapIdToSessionData.Clear();
+ m_vecVarObj.clear();
+ m_mapBrkPtIdToBrkPtInfo.clear();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Record information about a LLDB break point so that is can be recalled in other
+// commands or LLDB event handling functions.
+// Type: Method.
+// Args: vBrkPtId - (R) LLDB break point ID.
+// vrBrkPtInfo - (R) Break point information object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::RecordBrkPtInfo( const MIuint vnBrkPtId, const SBrkPtInfo & vrBrkPtInfo )
+{
+ MapPairBrkPtIdToBrkPtInfo_t pr( vnBrkPtId, vrBrkPtInfo );
+ m_mapBrkPtIdToBrkPtInfo.insert( pr );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve information about a LLDB break point previous recorded either by
+// commands or LLDB event handling functions.
+// Type: Method.
+// Args: vBrkPtId - (R) LLDB break point ID.
+// vrwBrkPtInfo - (W) Break point information object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::RecordBrkPtInfoGet( const MIuint vnBrkPtId, SBrkPtInfo & vrwBrkPtInfo ) const
+{
+ const MapBrkPtIdToBrkPtInfo_t::const_iterator it = m_mapBrkPtIdToBrkPtInfo.find( vnBrkPtId );
+ if( it != m_mapBrkPtIdToBrkPtInfo.end() )
+ {
+ vrwBrkPtInfo = (*it).second;
+ return MIstatus::success;
+ }
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Delete information about a specific LLDB break point object. This function
+// should be called when a LLDB break point is deleted.
+// Type: Method.
+// Args: vBrkPtId - (R) LLDB break point ID.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::RecordBrkPtInfoDelete( const MIuint vnBrkPtId )
+{
+ const MapBrkPtIdToBrkPtInfo_t::const_iterator it = m_mapBrkPtIdToBrkPtInfo.find( vnBrkPtId );
+ if( it != m_mapBrkPtIdToBrkPtInfo.end() )
+ {
+ m_mapBrkPtIdToBrkPtInfo.erase( it );
+ return MIstatus::success;
+ }
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the specified thread's frame information.
+// Type: Method.
+// Args: vCmdData - (R) A command's information.
+// vThreadIdx - (R) Thread index.
+// vwrThreadFrames - (W) Frame data.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::GetThreadFrames( const SMICmdData & vCmdData, const MIuint vThreadIdx, CMIUtilString & vwrThreadFrames )
+{
+ lldb::SBThread thread = m_lldbProcess.GetThreadByIndexID( vThreadIdx );
+ const uint32_t nFrames = thread.GetNumFrames();
+ if( nFrames == 0 )
+ {
+ // MI print "frame={}"
+ CMICmnMIValueTuple miValueTuple;
+ CMICmnMIValueResult miValueResult( "frame", miValueTuple );
+ vwrThreadFrames = miValueResult.GetString();
+ return MIstatus::success;
+ }
+
+ // MI print "frame={level=\"%d\",addr=\"0x%08llx\",func=\"%s\",args=[%s],file=\"%s\",fullname=\"%s\",line=\"%d\"},frame={level=\"%d\",addr=\"0x%08llx\",func=\"%s\",args=[%s],file=\"%s\",fullname=\"%s\",line=\"%d\"}, ..."
+ CMIUtilString strListCommaSeperated;
+ for( MIuint nLevel = 0; nLevel < nFrames; nLevel++ )
+ {
+ lldb::SBFrame frame = thread.GetFrameAtIndex( nLevel );
+ lldb::addr_t pc = 0;
+ CMIUtilString fnName;
+ CMIUtilString fileName;
+ CMIUtilString path;
+ MIuint nLine = 0;
+ if( !GetFrameInfo( frame, pc, fnName, fileName, path, nLine ) )
+ return MIstatus::failure;
+
+ // Function args
+ CMICmnMIValueList miValueList( true );
+ const MIuint maskVarTypes = 0x1000;
+ if( !MIResponseFormVariableInfo( frame, maskVarTypes, miValueList ) )
+ return MIstatus::failure;
+
+ const MIchar * pUnknown = "??";
+ if( fnName != pUnknown )
+ {
+ std::replace( fnName.begin(), fnName.end(), ')', ' ' );
+ std::replace( fnName.begin(), fnName.end(), '(', ' ' );
+ std::replace( fnName.begin(), fnName.end(), '\'', ' ' );
+ }
+
+ CMICmnMIValueTuple miValueTuple;
+ const CMIUtilString strLevel( CMIUtilString::Format( "%d", nLevel ) );
+ const CMICmnMIValueConst miValueConst( strLevel );
+ const CMICmnMIValueResult miValueResult( "level", miValueConst );
+ miValueTuple.Add( miValueResult );
+ if( !MIResponseFormFrameInfo2( pc, miValueList.GetString(), fnName, fileName, path, nLine, miValueTuple ) )
+ return MIstatus::failure;
+
+ const CMICmnMIValueResult miValueResult2( "frame", miValueTuple );
+ if( nLevel != 0 )
+ strListCommaSeperated += ",";
+ strListCommaSeperated += miValueResult2.GetString();
+ }
+
+ vwrThreadFrames = strListCommaSeperated;
+
+ return MIstatus::success;
+}
+
+// Todo: Refactor maybe to so only one function with this name, but not just yet
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the specified thread's frame information.
+// Type: Method.
+// Args: vCmdData - (R) A command's information.
+// vThreadIdx - (R) Thread index.
+// vwrThreadFrames - (W) Frame data.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::GetThreadFrames2( const SMICmdData & vCmdData, const MIuint vThreadIdx, CMIUtilString & vwrThreadFrames )
+{
+ lldb::SBThread thread = m_lldbProcess.GetThreadByIndexID( vThreadIdx );
+ const uint32_t nFrames = thread.GetNumFrames();
+ if( nFrames == 0 )
+ {
+ // MI print "frame={}"
+ CMICmnMIValueTuple miValueTuple;
+ CMICmnMIValueResult miValueResult( "frame", miValueTuple );
+ vwrThreadFrames = miValueResult.GetString();
+ return MIstatus::success;
+ }
+
+ // MI print "frame={level=\"%d\",addr=\"0x%08llx\",func=\"%s\",args=[%s],file=\"%s\",fullname=\"%s\",line=\"%d\"},frame={level=\"%d\",addr=\"0x%08llx\",func=\"%s\",args=[%s],file=\"%s\",fullname=\"%s\",line=\"%d\"}, ..."
+ CMIUtilString strListCommaSeperated;
+ for( MIuint nLevel = 0; nLevel < nFrames; nLevel++ )
+ {
+ lldb::SBFrame frame = thread.GetFrameAtIndex( nLevel );
+ lldb::addr_t pc = 0;
+ CMIUtilString fnName;
+ CMIUtilString fileName;
+ CMIUtilString path;
+ MIuint nLine = 0;
+ if( !GetFrameInfo( frame, pc, fnName, fileName, path, nLine ) )
+ return MIstatus::failure;
+
+ // Function args
+ CMICmnMIValueList miValueList( true );
+ const MIuint maskVarTypes = 0x1000;
+ if( !MIResponseFormVariableInfo2( frame, maskVarTypes, miValueList ) )
+ return MIstatus::failure;
+
+ const MIchar * pUnknown = "??";
+ if( fnName != pUnknown )
+ {
+ std::replace( fnName.begin(), fnName.end(), ')', ' ' );
+ std::replace( fnName.begin(), fnName.end(), '(', ' ' );
+ std::replace( fnName.begin(), fnName.end(), '\'', ' ' );
+ }
+
+ CMICmnMIValueTuple miValueTuple;
+ const CMIUtilString strLevel( CMIUtilString::Format( "%d", nLevel ) );
+ const CMICmnMIValueConst miValueConst( strLevel );
+ const CMICmnMIValueResult miValueResult( "level", miValueConst );
+ miValueTuple.Add( miValueResult );
+ if( !MIResponseFormFrameInfo2( pc, miValueList.GetString(), fnName, fileName, path, nLine, miValueTuple ) )
+ return MIstatus::failure;
+
+ const CMICmnMIValueResult miValueResult2( "frame", miValueTuple );
+ if( nLevel != 0 )
+ strListCommaSeperated += ",";
+ strListCommaSeperated += miValueResult2.GetString();
+ }
+
+ vwrThreadFrames = strListCommaSeperated;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Return the resolved file's path for the given file.
+// Type: Method.
+// Args: vCmdData - (R) A command's information.
+// vPath - (R) Original path.
+// vwrResolvedPath - (W) Resolved path.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::ResolvePath( const SMICmdData & vCmdData, const CMIUtilString & vPath, CMIUtilString & vwrResolvedPath )
+{
+ // ToDo: Verify this code as it does not work as vPath is always empty
+
+ CMIUtilString strResolvedPath;
+ if( !SharedDataRetrieve< CMIUtilString >( m_constStrSharedDataKeyWkDir, strResolvedPath ) )
+ {
+ vwrResolvedPath = "";
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_SHARED_DATA_NOT_FOUND ), vCmdData.strMiCmd.c_str(), m_constStrSharedDataKeyWkDir.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ vwrResolvedPath = vPath;
+
+ return ResolvePath( strResolvedPath, vwrResolvedPath );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Return the resolved file's path for the given file.
+// Type: Method.
+// Args: vstrUnknown - (R) String assigned to path when resolved path is empty.
+// vwrResolvedPath - (RW) The original path overwritten with resolved path.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::ResolvePath( const CMIUtilString & vstrUnknown, CMIUtilString & vwrResolvedPath )
+{
+ if( vwrResolvedPath.size() < 1 )
+ {
+ vwrResolvedPath = vstrUnknown;
+ return MIstatus::success;
+ }
+
+ bool bOk = MIstatus::success;
+
+ CMIUtilString::VecString_t vecPathFolders;
+ const MIuint nSplits = vwrResolvedPath.Split( "/", vecPathFolders ); MIunused( nSplits );
+ MIuint nFoldersBack = 1; // 1 is just the file (last element of vector)
+ while( bOk && (vecPathFolders.size() >= nFoldersBack) )
+ {
+ CMIUtilString strTestPath;
+ MIuint nFoldersToAdd = nFoldersBack;
+ while( nFoldersToAdd > 0 )
+ {
+ strTestPath += "/";
+ strTestPath += vecPathFolders[ vecPathFolders.size() - nFoldersToAdd ];
+ nFoldersToAdd--;
+ }
+ bool bYesAccessible = false;
+ bOk = AccessPath( strTestPath, bYesAccessible );
+ if( bYesAccessible )
+ {
+ vwrResolvedPath = strTestPath;
+ return MIstatus::success;
+ }
+ else
+ nFoldersBack++;
+ }
+
+ // No files exist in the union of working directory and debuginfo path
+ // Simply use the debuginfo path and let the IDE handle it.
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine the given file path exists or not.
+// Type: Method.
+// Args: vPath - (R) File name path.
+// vwbYesAccessible - (W) True - file exists, false = does not exist.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::AccessPath( const CMIUtilString & vPath, bool & vwbYesAccessible )
+{
+#ifdef _WIN32
+ vwbYesAccessible = (::_access( vPath.c_str(), 0 ) == 0);
+#else
+ vwbYesAccessible = (::access( vPath.c_str(), 0 ) == 0);
+#endif // _WIN32
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Form MI partial response by appending more MI value type objects to the
+// tuple type object past in.
+// Type: Method.
+// Args: vCmdData - (R) A command's information.
+// vrThread - (R) LLDB thread object.
+// vwrMIValueTuple - (W) MI value tuple object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::MIResponseFormThreadInfo( const SMICmdData & vCmdData, const lldb::SBThread & vrThread, CMICmnMIValueTuple & vwrMIValueTuple )
+{
+ lldb::SBThread & rThread = const_cast< lldb::SBThread & >( vrThread );
+
+ CMIUtilString strFrames;
+ if( !GetThreadFrames( vCmdData, rThread.GetIndexID(), strFrames ) )
+ return MIstatus::failure;
+
+ const bool bSuspended = rThread.IsSuspended();
+ const lldb::StopReason eReason = rThread.GetStopReason();
+ const bool bValidReason = !((eReason == lldb::eStopReasonNone) || (eReason == lldb::eStopReasonInvalid));
+ const CMIUtilString strState( (bSuspended || bValidReason) ? "stopped" : "running" );
+
+ // Add "id"
+ const CMIUtilString strId( CMIUtilString::Format( "%d", rThread.GetIndexID() ) );
+ const CMICmnMIValueConst miValueConst1( strId );
+ const CMICmnMIValueResult miValueResult1( "id", miValueConst1 );
+ if( !vwrMIValueTuple.Add( miValueResult1 ) )
+ return MIstatus::failure;
+
+ // Add "target-id"
+ const MIchar * pThreadName = rThread.GetName();
+ const MIuint len = (pThreadName != nullptr) ? CMIUtilString( pThreadName ).length() : 0;
+ const bool bHaveName = ((pThreadName != nullptr) && (len > 0) && (len < 32) && CMIUtilString::IsAllValidAlphaAndNumeric( *pThreadName ) ); // 32 is arbitary number
+ const MIchar * pThrdFmt = bHaveName ? "%s" : "Thread %d";
+ CMIUtilString strThread;
+ if( bHaveName )
+ strThread = CMIUtilString::Format( pThrdFmt, pThreadName );
+ else
+ strThread = CMIUtilString::Format( pThrdFmt, rThread.GetIndexID() );
+ const CMICmnMIValueConst miValueConst2( strThread );
+ const CMICmnMIValueResult miValueResult2( "target-id", miValueConst2 );
+ if( !vwrMIValueTuple.Add( miValueResult2 ) )
+ return MIstatus::failure;
+
+ // Add "frame"
+ const CMICmnMIValueConst miValueConst3( strFrames, true );
+ if( !vwrMIValueTuple.Add( miValueConst3, false ) )
+ return MIstatus::failure;
+
+ // Add "state"
+ const CMICmnMIValueConst miValueConst4( strState );
+ const CMICmnMIValueResult miValueResult4( "state", miValueConst4 );
+ if( !vwrMIValueTuple.Add( miValueResult4 ) )
+ return MIstatus::failure;
+
+ return MIstatus::success;
+}
+
+// Todo: Refactor maybe to so only one function with this name, but not just yet
+//++ ------------------------------------------------------------------------------------
+// Details: Form MI partial response by appending more MI value type objects to the
+// tuple type object past in.
+// Type: Method.
+// Args: vCmdData - (R) A command's information.
+// vrThread - (R) LLDB thread object.
+// vwrMIValueTuple - (W) MI value tuple object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::MIResponseFormThreadInfo3( const SMICmdData & vCmdData, const lldb::SBThread & vrThread, CMICmnMIValueTuple & vwrMIValueTuple )
+{
+ lldb::SBThread & rThread = const_cast< lldb::SBThread & >( vrThread );
+
+ CMIUtilString strFrames;
+ if( !GetThreadFrames2( vCmdData, rThread.GetIndexID(), strFrames ) )
+ return MIstatus::failure;
+
+ const bool bSuspended = rThread.IsSuspended();
+ const lldb::StopReason eReason = rThread.GetStopReason();
+ const bool bValidReason = !((eReason == lldb::eStopReasonNone) || (eReason == lldb::eStopReasonInvalid));
+ const CMIUtilString strState( (bSuspended || bValidReason) ? "stopped" : "running" );
+
+ // Add "id"
+ const CMIUtilString strId( CMIUtilString::Format( "%d", rThread.GetIndexID() ) );
+ const CMICmnMIValueConst miValueConst1( strId );
+ const CMICmnMIValueResult miValueResult1( "id", miValueConst1 );
+ if( !vwrMIValueTuple.Add( miValueResult1 ) )
+ return MIstatus::failure;
+
+ // Add "target-id"
+ const MIchar * pThreadName = rThread.GetName();
+ const MIuint len = (pThreadName != nullptr) ? CMIUtilString( pThreadName ).length() : 0;
+ const bool bHaveName = ((pThreadName != nullptr) && (len > 0) && (len < 32) && CMIUtilString::IsAllValidAlphaAndNumeric( *pThreadName ) ); // 32 is arbitary number
+ const MIchar * pThrdFmt = bHaveName ? "%s" : "Thread %d";
+ CMIUtilString strThread;
+ if( bHaveName )
+ strThread = CMIUtilString::Format( pThrdFmt, pThreadName );
+ else
+ strThread = CMIUtilString::Format( pThrdFmt, rThread.GetIndexID() );
+ const CMICmnMIValueConst miValueConst2( strThread );
+ const CMICmnMIValueResult miValueResult2( "target-id", miValueConst2 );
+ if( !vwrMIValueTuple.Add( miValueResult2 ) )
+ return MIstatus::failure;
+
+ // Add "frame"
+ const CMICmnMIValueConst miValueConst3( strFrames, true );
+ if( !vwrMIValueTuple.Add( miValueConst3, false ) )
+ return MIstatus::failure;
+
+ // Add "state"
+ const CMICmnMIValueConst miValueConst4( strState );
+ const CMICmnMIValueResult miValueResult4( "state", miValueConst4 );
+ if( !vwrMIValueTuple.Add( miValueResult4 ) )
+ return MIstatus::failure;
+
+ return MIstatus::success;
+}
+
+// Todo: Refactor maybe to so only one function with this name, but not just yet
+//++ ------------------------------------------------------------------------------------
+// Details: Form MI partial response by appending more MI value type objects to the
+// tuple type object past in.
+// Type: Method.
+// Args: vCmdData - (R) A command's information.
+// vrThread - (R) LLDB thread object.
+// vwrMIValueTuple - (W) MI value tuple object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::MIResponseFormThreadInfo2( const SMICmdData & vCmdData, const lldb::SBThread & vrThread, CMICmnMIValueTuple & vwrMIValueTuple )
+{
+ lldb::SBThread & rThread = const_cast< lldb::SBThread & >( vrThread );
+
+ const bool bSuspended = rThread.IsSuspended();
+ const lldb::StopReason eReason = rThread.GetStopReason();
+ const bool bValidReason = !((eReason == lldb::eStopReasonNone) || (eReason == lldb::eStopReasonInvalid));
+ const CMIUtilString strState( (bSuspended || bValidReason) ? "stopped" : "running" );
+
+ // Add "id"
+ const CMIUtilString strId( CMIUtilString::Format( "%d", rThread.GetIndexID() ) );
+ const CMICmnMIValueConst miValueConst1( strId );
+ const CMICmnMIValueResult miValueResult1( "id", miValueConst1 );
+ if( !vwrMIValueTuple.Add( miValueResult1 ) )
+ return MIstatus::failure;
+
+ // Add "target-id"
+ const MIchar * pThreadName = rThread.GetName();
+ const MIuint len = (pThreadName != nullptr) ? CMIUtilString( pThreadName ).length() : 0;
+ const bool bHaveName = ((pThreadName != nullptr) && (len > 0) && (len < 32) && CMIUtilString::IsAllValidAlphaAndNumeric( *pThreadName ) ); // 32 is arbitary number
+ const MIchar * pThrdFmt = bHaveName ? "%s" : "Thread %d";
+ CMIUtilString strThread;
+ if( bHaveName )
+ strThread = CMIUtilString::Format( pThrdFmt, pThreadName );
+ else
+ strThread = CMIUtilString::Format( pThrdFmt, rThread.GetIndexID() );
+ const CMICmnMIValueConst miValueConst2( strThread );
+ const CMICmnMIValueResult miValueResult2( "target-id", miValueConst2 );
+ if( !vwrMIValueTuple.Add( miValueResult2 ) )
+ return MIstatus::failure;
+
+ // Add "state"
+ const CMICmnMIValueConst miValueConst4( strState );
+ const CMICmnMIValueResult miValueResult4( "state", miValueConst4 );
+ if( !vwrMIValueTuple.Add( miValueResult4 ) )
+ return MIstatus::failure;
+
+ return MIstatus::success;
+}
+
+// Todo: Refactor maybe to so only one function with this name, but not just yet
+//++ ------------------------------------------------------------------------------------
+// Details: Form MI partial response by appending more MI value type objects to the
+// tuple type object past in.
+// Type: Method.
+// Args: vrFrame - (R) LLDB thread object.
+// vMaskVarTypes - (R) 0x1000 = arguments,
+// 0x0100 = locals,
+// 0x0010 = statics,
+// 0x0001 = in scope only.
+// vwrMIValueList - (W) MI value list object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::MIResponseFormVariableInfo2( const lldb::SBFrame & vrFrame, const MIuint vMaskVarTypes, CMICmnMIValueList & vwrMiValueList )
+{
+ bool bOk = MIstatus::success;
+ lldb::SBFrame & rFrame = const_cast< lldb::SBFrame & >( vrFrame );
+
+ const bool bArg = (vMaskVarTypes & 0x1000);
+ const bool bLocals = (vMaskVarTypes & 0x0100);
+ const bool bStatics = (vMaskVarTypes & 0x0010);
+ const bool bInScopeOnly = (vMaskVarTypes & 0x0001);
+ lldb::SBValueList listArg = rFrame.GetVariables( bArg, bLocals, bStatics, bInScopeOnly );
+ const MIuint nArgs = listArg.GetSize();
+ for( MIuint i = 0; bOk && (i < nArgs); i++ )
+ {
+ lldb::SBValue value = listArg.GetValueAtIndex( i );
+ const CMICmnLLDBUtilSBValue utilValue( value );
+ const CMICmnMIValueConst miValueConst( utilValue.GetName() );
+ const CMICmnMIValueResult miValueResult( "name", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ const CMICmnMIValueConst miValueConst2( utilValue.GetValue() );
+ const CMICmnMIValueResult miValueResult2( "value", miValueConst2 );
+ miValueTuple.Add( miValueResult2 );
+ bOk = vwrMiValueList.Add( miValueTuple );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Form MI partial response by appending more MI value type objects to the
+// tuple type object past in.
+// Type: Method.
+// Args: vrFrame - (R) LLDB thread object.
+// vMaskVarTypes - (R) 0x1000 = arguments,
+// 0x0100 = locals,
+// 0x0010 = statics,
+// 0x0001 = in scope only.
+// vwrMIValueList - (W) MI value list object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::MIResponseFormVariableInfo( const lldb::SBFrame & vrFrame, const MIuint vMaskVarTypes, CMICmnMIValueList & vwrMiValueList )
+{
+ bool bOk = MIstatus::success;
+ lldb::SBFrame & rFrame = const_cast< lldb::SBFrame & >( vrFrame );
+
+ const bool bArg = (vMaskVarTypes & 0x1000);
+ const bool bLocals = (vMaskVarTypes & 0x0100);
+ const bool bStatics = (vMaskVarTypes & 0x0010);
+ const bool bInScopeOnly = (vMaskVarTypes & 0x0001);
+ const MIuint nMaxRecusiveDepth = 10;
+ MIuint nCurrentRecursiveDepth = 0;
+ lldb::SBValueList listArg = rFrame.GetVariables( bArg, bLocals, bStatics, bInScopeOnly );
+ const MIuint nArgs = listArg.GetSize();
+ for( MIuint i = 0; bOk && (i < nArgs); i++ )
+ {
+ lldb::SBValue value = listArg.GetValueAtIndex( i );
+ bOk = GetVariableInfo( nMaxRecusiveDepth, value, false, vwrMiValueList, nCurrentRecursiveDepth );
+ }
+
+ return bOk;
+}
+
+// *** Do not refactor this function to be one function with same name as it can break more than
+// *** than one stack type command
+//++ ------------------------------------------------------------------------------------
+// Details: Form MI partial response by appending more MI value type objects to the
+// tuple type object past in.
+// Type: Method.
+// Args: vrFrame - (R) LLDB thread object.
+// vMaskVarTypes - (R) 0x1000 = arguments,
+// 0x0100 = locals,
+// 0x0010 = statics,
+// 0x0001 = in scope only.
+// vwrMIValueList - (W) MI value list object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::MIResponseFormVariableInfo3( const lldb::SBFrame & vrFrame, const MIuint vMaskVarTypes, CMICmnMIValueList & vwrMiValueList )
+{
+ bool bOk = MIstatus::success;
+ lldb::SBFrame & rFrame = const_cast< lldb::SBFrame & >( vrFrame );
+
+ const bool bArg = (vMaskVarTypes & 0x1000);
+ const bool bLocals = (vMaskVarTypes & 0x0100);
+ const bool bStatics = (vMaskVarTypes & 0x0010);
+ const bool bInScopeOnly = (vMaskVarTypes & 0x0001);
+ const MIuint nMaxRecusiveDepth = 10;
+ MIuint nCurrentRecursiveDepth = 0;
+ lldb::SBValueList listArg = rFrame.GetVariables( bArg, bLocals, bStatics, bInScopeOnly );
+ const MIuint nArgs = listArg.GetSize();
+ for( MIuint i = 0; bOk && (i < nArgs); i++ )
+ {
+ lldb::SBValue value = listArg.GetValueAtIndex( i );
+ bOk = GetVariableInfo2( nMaxRecusiveDepth, value, false, vwrMiValueList, nCurrentRecursiveDepth );
+ }
+
+ return bOk;
+}
+
+// *** Do not refactor this function to be one function with same name as it can break more than
+// *** than one stack type command
+//++ ------------------------------------------------------------------------------------
+// Details: Extract the value's name and value or recurse into child value object.
+// Type: Method.
+// Args: vnMaxDepth - (R) The max recursive depth for this function.
+// vrValue - (R) LLDB value object.
+// vbIsChildValue - (R) True = Value object is a child of a higher Value object,
+// - False = Value object not a child.
+// vwrMIValueList - (W) MI value list object.
+// vnDepth - (RW) The current recursive depth of this function.
+// // Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::GetVariableInfo( const MIuint vnMaxDepth, const lldb::SBValue & vrValue, const bool vbIsChildValue, CMICmnMIValueList & vwrMiValueList, MIuint & vrwnDepth )
+{
+ // *** Update GetVariableInfo2() with any code changes here ***
+
+ // Check recursive depth
+ if( vrwnDepth >= vnMaxDepth )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( vrValue );
+ const CMICmnLLDBUtilSBValue utilValue( vrValue, true );
+ CMICmnMIValueTuple miValueTuple;
+ const MIchar * pName = rValue.GetName(); MIunused( pName );
+ const bool bIsPointerType = rValue.GetType().IsPointerType();
+ const MIuint nChildren = rValue.GetNumChildren();
+ if( nChildren == 0 )
+ {
+ if( vbIsChildValue )
+ {
+ if( utilValue.IsCharType() )
+ {
+ // For char types and try to form text string
+ const CMICmnMIValueConst miValueConst( utilValue.GetValue().c_str(), true );
+ miValueTuple.Add( miValueConst, true );
+ }
+ else
+ {
+ // For composite types
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "%s = %s", utilValue.GetName().c_str(), utilValue.GetValue().c_str() ), true );
+ miValueTuple.Add( miValueConst, true );
+ }
+ return vwrMiValueList.Add( CMICmnMIValueConst( miValueTuple.ExtractContentNoBrackets(), true ) );
+ }
+ else
+ {
+ // Basic types
+ const CMICmnMIValueConst miValueConst( utilValue.GetName() );
+ const CMICmnMIValueResult miValueResult( "name", miValueConst );
+ miValueTuple.Add( miValueResult );
+ const CMICmnMIValueConst miValueConst2( utilValue.GetValue() );
+ const CMICmnMIValueResult miValueResult2( "value", miValueConst2 );
+ miValueTuple.Add( miValueResult2 );
+ return vwrMiValueList.Add( miValueTuple );
+ }
+ }
+ else if( bIsPointerType && utilValue.IsChildCharType() )
+ {
+ // Append string text to the parent value information
+ const CMICmnMIValueConst miValueConst( utilValue.GetName() );
+ const CMICmnMIValueResult miValueResult( "name", miValueConst );
+ miValueTuple.Add( miValueResult );
+
+ const CMIUtilString & rText( utilValue.GetChildValueCString() );
+ if( rText.empty() )
+ {
+ const CMICmnMIValueConst miValueConst( utilValue.GetValue() );
+ const CMICmnMIValueResult miValueResult( "value", miValueConst );
+ miValueTuple.Add( miValueResult );
+ }
+ else
+ {
+ if( utilValue.IsValueUnknown() )
+ {
+ const CMICmnMIValueConst miValueConst( rText );
+ const CMICmnMIValueResult miValueResult( "value", miValueConst );
+ miValueTuple.Add( miValueResult );
+ }
+ else
+ {
+ // Note code that has const in will not show the text suffix to the string pointer
+ // i.e. const char * pMyStr = "blah"; ==> "0x00007000"" <-- Eclipse shows this
+ // but char * pMyStr = "blah"; ==> "0x00007000" "blah"" <-- Eclipse shows this
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "%s %s", utilValue.GetValue().c_str(), rText.c_str() ) );
+ const CMICmnMIValueResult miValueResult( "value", miValueConst );
+ miValueTuple.Add( miValueResult );
+ }
+ }
+ return vwrMiValueList.Add( miValueTuple );
+ }
+ else if( bIsPointerType )
+ {
+ if( vbIsChildValue )
+ {
+ // For composite types
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "%s = %s", utilValue.GetName().c_str(), utilValue.GetValue().c_str() ), true );
+ miValueTuple.Add( miValueConst, true );
+ return vwrMiValueList.Add( CMICmnMIValueConst( miValueTuple.ExtractContentNoBrackets(), true ) );
+ }
+ else
+ {
+ // Basic types
+ const CMICmnMIValueConst miValueConst( utilValue.GetName() );
+ const CMICmnMIValueResult miValueResult( "name", miValueConst );
+ miValueTuple.Add( miValueResult );
+ const CMICmnMIValueConst miValueConst2( utilValue.GetValue() );
+ const CMICmnMIValueResult miValueResult2( "value", miValueConst2 );
+ miValueTuple.Add( miValueResult2 );
+ return vwrMiValueList.Add( miValueTuple );
+ }
+ }
+ else
+ {
+ // Build parent child composite types
+ CMICmnMIValueList miValueList( true );
+ for( MIuint i = 0; bOk && (i < nChildren); i++ )
+ {
+ lldb::SBValue member = rValue.GetChildAtIndex( i );
+ bOk = GetVariableInfo( vnMaxDepth, member, true, miValueList, ++vrwnDepth );
+ }
+ const CMICmnMIValueConst miValueConst( utilValue.GetName() );
+ const CMICmnMIValueResult miValueResult( "name", miValueConst );
+ miValueTuple.Add( miValueResult );
+ const CMICmnMIValueConst miValueConst2( CMIUtilString::Format( "{%s}", miValueList.ExtractContentNoBrackets().c_str() ) );
+ const CMICmnMIValueResult miValueResult2( "value", miValueConst2 );
+ miValueTuple.Add( miValueResult2 );
+ return vwrMiValueList.Add( miValueTuple );
+ }
+}
+
+// *** Do not refactor this function to be one function with same name as it can break more than
+// *** than one stack type command
+//++ ------------------------------------------------------------------------------------
+// Details: Extract the value's name and value or recurse into child value object.
+// Type: Method.
+// Args: vnMaxDepth - (R) The max recursive depth for this function.
+// vrValue - (R) LLDB value object.
+// vbIsChildValue - (R) True = Value object is a child of a higher Value object,
+// - False = Value object not a child.
+// vwrMIValueList - (W) MI value list object.
+// vnDepth - (RW) The current recursive depth of this function.
+// // Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::GetVariableInfo2( const MIuint vnMaxDepth, const lldb::SBValue & vrValue, const bool vbIsChildValue, CMICmnMIValueList & vwrMiValueList, MIuint & vrwnDepth )
+{
+ // *** Update GetVariableInfo() with any code changes here ***
+
+ // Check recursive depth
+ if( vrwnDepth >= vnMaxDepth )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( vrValue );
+ const CMICmnLLDBUtilSBValue utilValue( vrValue, true );
+ CMICmnMIValueTuple miValueTuple;
+ const MIchar * pName = rValue.GetName(); MIunused( pName );
+ const MIuint nChildren = rValue.GetNumChildren();
+ if( nChildren == 0 )
+ {
+ if( vbIsChildValue && utilValue.IsCharType() )
+ {
+ // For char types and try to form text string
+ const CMICmnMIValueConst miValueConst( utilValue.GetValue().c_str(), true );
+ miValueTuple.Add( miValueConst, true );
+ return vwrMiValueList.Add( CMICmnMIValueConst( miValueTuple.ExtractContentNoBrackets(), true ) );
+ }
+ else
+ {
+ // Basic types
+ const CMICmnMIValueConst miValueConst( utilValue.GetName() );
+ const CMICmnMIValueResult miValueResult( "name", miValueConst );
+ miValueTuple.Add( miValueResult );
+ const CMICmnMIValueConst miValueConst2( utilValue.GetValue() );
+ const CMICmnMIValueResult miValueResult2( "value", miValueConst2 );
+ miValueTuple.Add( miValueResult2 );
+ return vwrMiValueList.Add( miValueTuple );
+ }
+ }
+ else if( utilValue.IsChildCharType() )
+ {
+ // Append string text to the parent value information
+ const CMICmnMIValueConst miValueConst( utilValue.GetName() );
+ const CMICmnMIValueResult miValueResult( "name", miValueConst );
+ miValueTuple.Add( miValueResult );
+
+ const CMIUtilString & rText( utilValue.GetChildValueCString() );
+ if( rText.empty() )
+ {
+ const CMICmnMIValueConst miValueConst( utilValue.GetValue() );
+ const CMICmnMIValueResult miValueResult( "value", miValueConst );
+ miValueTuple.Add( miValueResult );
+ }
+ else
+ {
+ if( utilValue.IsValueUnknown() )
+ {
+ const CMICmnMIValueConst miValueConst( rText );
+ const CMICmnMIValueResult miValueResult( "value", miValueConst );
+ miValueTuple.Add( miValueResult );
+ }
+ else
+ {
+ // Note code that has const in will not show the text suffix to the string pointer
+ // i.e. const char * pMyStr = "blah"; ==> "0x00007000"" <-- Eclipse shows this
+ // but char * pMyStr = "blah"; ==> "0x00007000" "blah"" <-- Eclipse shows this
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "%s %s", utilValue.GetValue().c_str(), rText.c_str() ) );
+ const CMICmnMIValueResult miValueResult( "value", miValueConst );
+ miValueTuple.Add( miValueResult );
+ }
+ }
+ return vwrMiValueList.Add( miValueTuple );
+ }
+ else
+ {
+ // Build parent child composite types
+ CMICmnMIValueList miValueList( true );
+ for( MIuint i = 0; bOk && (i < nChildren); i++ )
+ {
+ lldb::SBValue member = rValue.GetChildAtIndex( i );
+ bOk = GetVariableInfo( vnMaxDepth, member, true, miValueList, ++vrwnDepth );
+ }
+ const CMICmnMIValueConst miValueConst( utilValue.GetName() );
+ const CMICmnMIValueResult miValueResult( "name", miValueConst );
+ miValueTuple.Add( miValueResult );
+ const CMICmnMIValueConst miValueConst2( CMIUtilString::Format( "{%s}", miValueList.ExtractContentNoBrackets().c_str() ) );
+ const CMICmnMIValueResult miValueResult2( "value", miValueConst2 );
+ miValueTuple.Add( miValueResult2 );
+ return vwrMiValueList.Add( miValueTuple );
+ }
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Form MI partial response by appending more MI value type objects to the
+// tuple type object past in.
+// Type: Method.
+// Args: vrThread - (R) LLDB thread object.
+// vwrMIValueTuple - (W) MI value tuple object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::MIResponseFormFrameInfo( const lldb::SBThread & vrThread, const MIuint vnLevel, CMICmnMIValueTuple & vwrMiValueTuple )
+{
+ lldb::SBThread & rThread = const_cast< lldb::SBThread & >( vrThread );
+
+ lldb::SBFrame frame = rThread.GetFrameAtIndex( vnLevel );
+ lldb::addr_t pc = 0;
+ CMIUtilString fnName;
+ CMIUtilString fileName;
+ CMIUtilString path;
+ MIuint nLine = 0;
+ if( !GetFrameInfo( frame, pc, fnName, fileName, path, nLine ) )
+ return MIstatus::failure;
+
+ // MI print "{level=\"0\",addr=\"0x%08llx\",func=\"%s\",file=\"%s\",fullname=\"%s\",line=\"%d\"}"
+ const CMIUtilString strLevel( CMIUtilString::Format( "%d", vnLevel ) );
+ const CMICmnMIValueConst miValueConst( strLevel );
+ const CMICmnMIValueResult miValueResult( "level", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ if( !MIResponseFormFrameInfo( pc, fnName, fileName, path, nLine, miValueTuple ) )
+ return MIstatus::failure;
+
+ vwrMiValueTuple = miValueTuple;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the frame information from LLDB frame object.
+// Type: Method.
+// Args: vrFrame - (R) LLDB thread object.
+// vPc - (W) Address number.
+// vFnName - (W) Function name.
+// vFileName - (W) File name text.
+// vPath - (W) Full file name and path text.
+// vnLine - (W) File line number.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::GetFrameInfo( const lldb::SBFrame & vrFrame, lldb::addr_t & vwPc, CMIUtilString & vwFnName, CMIUtilString & vwFileName, CMIUtilString & vwPath, MIuint & vwnLine )
+{
+ lldb::SBFrame & rFrame = const_cast< lldb::SBFrame & >( vrFrame );
+
+ static char pBuffer[ MAX_PATH ];
+ const MIuint nBytes = rFrame.GetLineEntry().GetFileSpec().GetPath( &pBuffer[ 0 ], sizeof( pBuffer ) ); MIunused( nBytes );
+ CMIUtilString strResolvedPath( &pBuffer[ 0 ] );
+ const MIchar * pUnkwn = "??";
+ if( !ResolvePath( pUnkwn, strResolvedPath ) )
+ return MIstatus::failure;
+ vwPath = strResolvedPath;
+
+ vwPc = rFrame.GetPC();
+
+ const MIchar * pFnName = rFrame.GetFunctionName();
+ vwFnName = (pFnName != nullptr) ? pFnName : pUnkwn;
+
+ const MIchar * pFileName = rFrame.GetLineEntry().GetFileSpec().GetFilename();
+ vwFileName = (pFileName != nullptr) ? pFileName : pUnkwn;
+
+ vwnLine = rFrame.GetLineEntry().GetLine();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Form MI partial response by appending more MI value type objects to the
+// tuple type object past in.
+// Type: Method.
+// Args: vPc - (R) Address number.
+// vFnName - (R) Function name.
+// vFileName - (R) File name text.
+// vPath - (R) Full file name and path text.
+// vnLine - (R) File line number.
+// vwrMIValueTuple - (W) MI value tuple object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::MIResponseFormFrameInfo( const lldb::addr_t vPc, const CMIUtilString & vFnName, const CMIUtilString & vFileName, const CMIUtilString & vPath, const MIuint vnLine, CMICmnMIValueTuple & vwrMiValueTuple )
+{
+ const CMIUtilString strAddr( CMIUtilString::Format( "0x%08llx", vPc ) );
+ const CMICmnMIValueConst miValueConst2( strAddr );
+ const CMICmnMIValueResult miValueResult2( "addr", miValueConst2 );
+ if( !vwrMiValueTuple.Add( miValueResult2 ) )
+ return MIstatus::failure;
+ const CMICmnMIValueConst miValueConst3( vFnName );
+ const CMICmnMIValueResult miValueResult3( "func", miValueConst3 );
+ if( !vwrMiValueTuple.Add( miValueResult3 ) )
+ return MIstatus::failure;
+ const CMICmnMIValueConst miValueConst5( vFileName );
+ const CMICmnMIValueResult miValueResult5( "file", miValueConst5 );
+ if( !vwrMiValueTuple.Add( miValueResult5 ) )
+ return MIstatus::failure;
+ const CMICmnMIValueConst miValueConst6( vPath );
+ const CMICmnMIValueResult miValueResult6( "fullname", miValueConst6 );
+ if( !vwrMiValueTuple.Add( miValueResult6 ) )
+ return MIstatus::failure;
+ const CMIUtilString strLine( CMIUtilString::Format( "%d", vnLine ) );
+ const CMICmnMIValueConst miValueConst7( strLine );
+ const CMICmnMIValueResult miValueResult7( "line", miValueConst7 );
+ if( !vwrMiValueTuple.Add( miValueResult7 ) )
+ return MIstatus::failure;
+
+ return MIstatus::success;
+}
+
+// Todo: Refactor maybe to so only one function with this name, but not just yet
+//++ ------------------------------------------------------------------------------------
+// Details: Form MI partial response by appending more MI value type objects to the
+// tuple type object past in.
+// Type: Method.
+// Args: vPc - (R) Address number.
+// vArgInfo - (R) Args information in MI response form.
+// vFnName - (R) Function name.
+// vFileName - (R) File name text.
+// vPath - (R) Full file name and path text.
+// vnLine - (R) File line number.
+// vwrMIValueTuple - (W) MI value tuple object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::MIResponseFormFrameInfo2( const lldb::addr_t vPc, const CMIUtilString & vArgInfo, const CMIUtilString & vFnName, const CMIUtilString & vFileName, const CMIUtilString & vPath, const MIuint vnLine, CMICmnMIValueTuple & vwrMiValueTuple )
+{
+ const CMIUtilString strAddr( CMIUtilString::Format( "0x%08llx", vPc ) );
+ const CMICmnMIValueConst miValueConst2( strAddr );
+ const CMICmnMIValueResult miValueResult2( "addr", miValueConst2 );
+ if( !vwrMiValueTuple.Add( miValueResult2 ) )
+ return MIstatus::failure;
+ const CMICmnMIValueConst miValueConst3( vFnName );
+ const CMICmnMIValueResult miValueResult3( "func", miValueConst3 );
+ if( !vwrMiValueTuple.Add( miValueResult3 ) )
+ return MIstatus::failure;
+ const CMICmnMIValueConst miValueConst4( vArgInfo, true );
+ const CMICmnMIValueResult miValueResult4( "args", miValueConst4 );
+ if( !vwrMiValueTuple.Add( miValueResult4 ) )
+ return MIstatus::failure;
+ const CMICmnMIValueConst miValueConst5( vFileName );
+ const CMICmnMIValueResult miValueResult5( "file", miValueConst5 );
+ if( !vwrMiValueTuple.Add( miValueResult5 ) )
+ return MIstatus::failure;
+ const CMICmnMIValueConst miValueConst6( vPath );
+ const CMICmnMIValueResult miValueResult6( "fullname", miValueConst6 );
+ if( !vwrMiValueTuple.Add( miValueResult6 ) )
+ return MIstatus::failure;
+ const CMIUtilString strLine( CMIUtilString::Format( "%d", vnLine ) );
+ const CMICmnMIValueConst miValueConst7( strLine );
+ const CMICmnMIValueResult miValueResult7( "line", miValueConst7 );
+ if( !vwrMiValueTuple.Add( miValueResult7 ) )
+ return MIstatus::failure;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Form MI partial response by appending more MI value type objects to the
+// tuple type object past in.
+// Type: Method.
+// Args: vrBrkPtInfo - (R) Break point information object.
+// vwrMIValueTuple - (W) MI value tuple object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::MIResponseFormBrkPtFrameInfo( const SBrkPtInfo & vrBrkPtInfo, CMICmnMIValueTuple & vwrMiValueTuple )
+{
+ const CMIUtilString strAddr( CMIUtilString::Format( "0x%08llx", vrBrkPtInfo.m_pc ) );
+ const CMICmnMIValueConst miValueConst2( strAddr );
+ const CMICmnMIValueResult miValueResult2( "addr", miValueConst2 );
+ if( !vwrMiValueTuple.Add( miValueResult2 ) )
+ return MIstatus::failure;
+ const CMICmnMIValueConst miValueConst3( vrBrkPtInfo.m_fnName );
+ const CMICmnMIValueResult miValueResult3( "func", miValueConst3 );
+ if( !vwrMiValueTuple.Add( miValueResult3 ) )
+ return MIstatus::failure;
+ const CMICmnMIValueConst miValueConst5( vrBrkPtInfo.m_fileName );
+ const CMICmnMIValueResult miValueResult5( "file", miValueConst5 );
+ if( !vwrMiValueTuple.Add( miValueResult5 ) )
+ return MIstatus::failure;
+ const CMIUtilString strN5 = CMIUtilString::Format( "%s/%s", vrBrkPtInfo.m_path.c_str(), vrBrkPtInfo.m_fileName.c_str() );
+ const CMICmnMIValueConst miValueConst6( strN5 );
+ const CMICmnMIValueResult miValueResult6( "fullname", miValueConst6 );
+ if( !vwrMiValueTuple.Add( miValueResult6 ) )
+ return MIstatus::failure;
+ const CMIUtilString strLine( CMIUtilString::Format( "%d", vrBrkPtInfo.m_nLine ) );
+ const CMICmnMIValueConst miValueConst7( strLine );
+ const CMICmnMIValueResult miValueResult7( "line", miValueConst7 );
+ if( !vwrMiValueTuple.Add( miValueResult7 ) )
+ return MIstatus::failure;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Form MI partial response by appending more MI value type objects to the
+// tuple type object past in.
+// Type: Method.
+// Args: vrBrkPtInfo - (R) Break point information object.
+// vwrMIValueTuple - (W) MI value tuple object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::MIResponseFormBrkPtInfo( const SBrkPtInfo & vrBrkPtInfo, CMICmnMIValueTuple & vwrMiValueTuple )
+{
+ // MI print "=breakpoint-modified,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%08x\", func=\"%s\",file=\"%s\",fullname=\"%s/%s\",line=\"%d\",times=\"%d\",original-location=\"%s\"}"
+
+ // "number="
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "%d", vrBrkPtInfo.m_id ) );
+ const CMICmnMIValueResult miValueResult( "number", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ // "type="
+ const CMICmnMIValueConst miValueConst2( vrBrkPtInfo.m_strType );
+ const CMICmnMIValueResult miValueResult2( "type", miValueConst2 );
+ bool bOk = miValueTuple.Add( miValueResult2 );
+ // "disp="
+ const CMICmnMIValueConst miValueConst3( vrBrkPtInfo.m_bDisp ? "del" : "keep" );
+ const CMICmnMIValueResult miValueResult3( "disp", miValueConst3 );
+ bOk = bOk && miValueTuple.Add( miValueResult3 );
+ // "enabled="
+ const CMICmnMIValueConst miValueConst4( vrBrkPtInfo.m_bEnabled ? "y" : "n" );
+ const CMICmnMIValueResult miValueResult4( "enabled", miValueConst4 );
+ bOk = bOk && miValueTuple.Add( miValueResult4 );
+ // "addr="
+ // "func="
+ // "file="
+ // "fullname="
+ // "line="
+ bOk = bOk && MIResponseFormBrkPtFrameInfo( vrBrkPtInfo, miValueTuple );
+ // "pending="
+ if( vrBrkPtInfo.m_bPending )
+ {
+ const CMICmnMIValueConst miValueConst( vrBrkPtInfo.m_strOrigLoc );
+ const CMICmnMIValueList miValueList( miValueConst );
+ const CMICmnMIValueResult miValueResult( "pending", miValueList );
+ bOk = bOk && miValueTuple.Add( miValueResult );
+ }
+ if( vrBrkPtInfo.m_bHaveArgOptionThreadGrp )
+ {
+ const CMICmnMIValueConst miValueConst( vrBrkPtInfo.m_strOptThrdGrp );
+ const CMICmnMIValueList miValueList( miValueConst );
+ const CMICmnMIValueResult miValueResult( "thread-groups", miValueList );
+ bOk = bOk && miValueTuple.Add( miValueResult );
+ }
+ // "times="
+ const CMICmnMIValueConst miValueConstB( CMIUtilString::Format( "%d", vrBrkPtInfo.m_nTimes ) );
+ const CMICmnMIValueResult miValueResultB( "times", miValueConstB );
+ bOk = bOk && miValueTuple.Add( miValueResultB );
+ // "thread="
+ if( vrBrkPtInfo.m_bBrkPtThreadId )
+ {
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "%d", vrBrkPtInfo.m_nBrkPtThreadId ) );
+ const CMICmnMIValueResult miValueResult( "thread", miValueConst );
+ bOk = bOk && miValueTuple.Add( miValueResult );
+ }
+ // "cond="
+ if( vrBrkPtInfo.m_bCondition )
+ {
+ const CMICmnMIValueConst miValueConst( vrBrkPtInfo.m_strCondition );
+ const CMICmnMIValueResult miValueResult( "cond", miValueConst );
+ bOk = bOk && miValueTuple.Add( miValueResult );
+ }
+ // "ignore="
+ if( vrBrkPtInfo.m_nIgnore != 0 )
+ {
+ const CMICmnMIValueConst miValueConst( CMIUtilString::Format( "%d", vrBrkPtInfo.m_nIgnore ) );
+ const CMICmnMIValueResult miValueResult( "ignore", miValueConst );
+ bOk = bOk && miValueTuple.Add( miValueResult );
+ }
+ // "original-location="
+ const CMICmnMIValueConst miValueConstC( vrBrkPtInfo.m_strOrigLoc );
+ const CMICmnMIValueResult miValueResultC( "original-location", miValueConstC );
+ bOk = bOk && miValueTuple.Add( miValueResultC );
+
+ vwrMiValueTuple = miValueTuple;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve breakpoint information and write into the given breakpoint information
+// object. Note not all possible information is retrieved and so the information
+// object may need to be filled in with more information after calling this
+// function. Mainly breakpoint location information of information that is
+// unlikely to change.
+// Type: Method.
+// Args: vBrkPt - (R) LLDB break point object.
+// vrBrkPtInfo - (W) Break point information object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfo::GetBrkPtInfo( const lldb::SBBreakpoint & vBrkPt, SBrkPtInfo & vrwBrkPtInfo ) const
+{
+ lldb::SBBreakpoint & rBrkPt = const_cast< lldb::SBBreakpoint & >( vBrkPt );
+ lldb::SBBreakpointLocation brkPtLoc = rBrkPt.GetLocationAtIndex( 0 );
+ lldb::SBAddress brkPtAddr = brkPtLoc.GetAddress();
+ lldb::SBSymbolContext symbolCntxt = brkPtAddr.GetSymbolContext( lldb::eSymbolContextEverything );
+ const MIchar * pUnkwn = "??";
+ lldb::SBModule rModule = symbolCntxt.GetModule();
+ const MIchar * pModule = rModule.IsValid() ? rModule.GetFileSpec().GetFilename() : pUnkwn; MIunused( pModule );
+ const MIchar * pFile = pUnkwn;
+ const MIchar * pFn = pUnkwn;
+ const MIchar * pFilePath = pUnkwn;
+ size_t nLine = 0;
+ const size_t nAddr = brkPtAddr.GetLoadAddress( m_lldbTarget );
+
+ lldb::SBCompileUnit rCmplUnit = symbolCntxt.GetCompileUnit();
+ if( rCmplUnit.IsValid() )
+ {
+ lldb::SBFileSpec rFileSpec = rCmplUnit.GetFileSpec();
+ pFile = rFileSpec.GetFilename();
+ pFilePath = rFileSpec.GetDirectory();
+ lldb::SBFunction rFn = symbolCntxt.GetFunction();
+ if( rFn.IsValid() )
+ pFn = rFn.GetName();
+ lldb::SBLineEntry rLnEntry = symbolCntxt.GetLineEntry();
+ if( rLnEntry.GetLine() > 0 )
+ nLine = rLnEntry.GetLine();
+ }
+
+ vrwBrkPtInfo.m_id = vBrkPt.GetID();
+ vrwBrkPtInfo.m_strType = "breakpoint";
+ vrwBrkPtInfo.m_pc = nAddr;
+ vrwBrkPtInfo.m_fnName = pFn;
+ vrwBrkPtInfo.m_fileName = pFile;
+ vrwBrkPtInfo.m_path = pFilePath;
+ vrwBrkPtInfo.m_nLine = nLine;
+ vrwBrkPtInfo.m_nTimes = vBrkPt.GetHitCount();
+
+ return MIstatus::success;
+}
diff --git a/tools/lldb-mi/MICmnLLDBDebugSessionInfo.h b/tools/lldb-mi/MICmnLLDBDebugSessionInfo.h
new file mode 100644
index 000000000000..ca7ea27f5611
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBDebugSessionInfo.h
@@ -0,0 +1,236 @@
+//===-- MICmnLLDBDebugSessionInfo.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBDebugSessionInfo.h
+//
+// Overview: CMICmnLLDBDebugSessionInfo interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <map>
+#include <vector>
+#include <lldb/API/SBDebugger.h>
+#include <lldb/API/SBListener.h>
+#include <lldb/API/SBProcess.h>
+#include <lldb/API/SBTarget.h>
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MIUtilSingletonBase.h"
+#include "MICmnLLDBDebugSessionInfoVarObj.h"
+#include "MICmnMIValueTuple.h"
+#include "MIUtilMapIdToVariant.h"
+
+// Declarations:
+class CMICmnLLDBDebugger;
+struct SMICmdData;
+class CMICmnMIValueTuple;
+class CMICmnMIValueList;
+
+//++ ============================================================================
+// Details: MI debug session object that holds debugging information between
+// instances of MI commands executing their work and producing MI
+// result records. Information/data is set by one or many commands then
+// retrieved by the same or other sebsequent commands.
+// It primarily to hold LLDB type objects.
+// A singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 04/03/2014.
+// Changes: None.
+//--
+class CMICmnLLDBDebugSessionInfo
+: public CMICmnBase
+, public MI::ISingleton< CMICmnLLDBDebugSessionInfo >
+{
+ friend class MI::ISingleton< CMICmnLLDBDebugSessionInfo >;
+
+// Structs:
+public:
+ //++ ============================================================================
+ // Details: Break point information object. Used to easily pass information about
+ // a break around and record break point information to be recalled by
+ // other commands or LLDB event handling functions.
+ //--
+ struct SBrkPtInfo
+ {
+ SBrkPtInfo( void )
+ : m_id( 0 )
+ , m_bDisp( false )
+ , m_bEnabled( false )
+ , m_pc( 0 )
+ , m_nLine( 0 )
+ , m_bHaveArgOptionThreadGrp( false )
+ , m_nTimes( 0 )
+ , m_bPending( false )
+ , m_nIgnore( 0 )
+ , m_bCondition( false )
+ , m_bBrkPtThreadId( false )
+ , m_nBrkPtThreadId( 0 )
+ {
+ }
+
+ MIuint m_id; // LLDB break point ID.
+ CMIUtilString m_strType; // Break point type.
+ bool m_bDisp ; // True = "del", false = "keep".
+ bool m_bEnabled; // True = enabled, false = disabled break point.
+ MIuint m_pc; // Address number.
+ CMIUtilString m_fnName; // Function name.
+ CMIUtilString m_fileName; // File name text.
+ CMIUtilString m_path; // Full file name and path text.
+ MIuint m_nLine; // File line number.
+ bool m_bHaveArgOptionThreadGrp; // True = include MI field, false = do not include "thread-groups".
+ CMIUtilString m_strOptThrdGrp; // Thread group number.
+ MIuint m_nTimes; // The count of the breakpoint existence.
+ CMIUtilString m_strOrigLoc; // The name of the break point.
+ bool m_bPending; // True = the breakpoint has not been established yet, false = location found
+ MIuint m_nIgnore; // The number of time the breakpoint is run over before it is stopped on a hit
+ bool m_bCondition; // True = break point is conditional, use condition expression, false = no condition
+ CMIUtilString m_strCondition; // Break point condition expression
+ bool m_bBrkPtThreadId; // True = break point is specified to work with a specific thread, false = no specified thread given
+ MIuint m_nBrkPtThreadId; // Restrict the breakpoint to the specified thread-id
+ };
+
+// Typedefs:
+public:
+ typedef std::vector< uint32_t > VecActiveThreadId_t;
+
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+
+ // Variant type data which can be assigned and retrieved across all command instances
+ template< typename T >
+ bool SharedDataAdd( const CMIUtilString & vKey, const T & vData );
+ template< typename T >
+ bool SharedDataRetrieve( const CMIUtilString & vKey, T & vwData );
+ bool SharedDataDestroy( void );
+
+ // Common command required functionality
+ bool AccessPath( const CMIUtilString & vPath, bool & vwbYesAccessible );
+ bool GetFrameInfo( const lldb::SBFrame & vrFrame, lldb::addr_t & vwPc, CMIUtilString & vwFnName, CMIUtilString & vwFileName, CMIUtilString & vwPath, MIuint & vwnLine );
+ bool GetThreadFrames( const SMICmdData & vCmdData, const MIuint vThreadIdx, CMIUtilString & vwrThreadFrames );
+ bool GetThreadFrames2( const SMICmdData & vCmdData, const MIuint vThreadIdx, CMIUtilString & vwrThreadFrames );
+ bool ResolvePath( const SMICmdData & vCmdData, const CMIUtilString & vPath, CMIUtilString & vwrResolvedPath );
+ bool ResolvePath( const CMIUtilString & vstrUnknown, CMIUtilString & vwrResolvedPath );
+ bool MIResponseFormFrameInfo( const lldb::SBThread & vrThread, const MIuint vnLevel, CMICmnMIValueTuple & vwrMiValueTuple );
+ bool MIResponseFormFrameInfo( const lldb::addr_t vPc, const CMIUtilString & vFnName, const CMIUtilString & vFileName, const CMIUtilString & vPath, const MIuint vnLine, CMICmnMIValueTuple & vwrMiValueTuple );
+ bool MIResponseFormFrameInfo2( const lldb::addr_t vPc, const CMIUtilString & vArgInfo, const CMIUtilString & vFnName, const CMIUtilString & vFileName, const CMIUtilString & vPath, const MIuint vnLine, CMICmnMIValueTuple & vwrMiValueTuple );
+ bool MIResponseFormThreadInfo( const SMICmdData & vCmdData, const lldb::SBThread & vrThread, CMICmnMIValueTuple & vwrMIValueTuple );
+ bool MIResponseFormThreadInfo2( const SMICmdData & vCmdData, const lldb::SBThread & vrThread, CMICmnMIValueTuple & vwrMIValueTuple );
+ bool MIResponseFormThreadInfo3( const SMICmdData & vCmdData, const lldb::SBThread & vrThread, CMICmnMIValueTuple & vwrMIValueTuple );
+ bool MIResponseFormVariableInfo( const lldb::SBFrame & vrFrame, const MIuint vMaskVarTypes, CMICmnMIValueList & vwrMiValueList );
+ bool MIResponseFormVariableInfo2( const lldb::SBFrame & vrFrame, const MIuint vMaskVarTypes, CMICmnMIValueList & vwrMiValueList );
+ bool MIResponseFormVariableInfo3( const lldb::SBFrame & vrFrame, const MIuint vMaskVarTypes, CMICmnMIValueList & vwrMiValueList );
+ bool MIResponseFormBrkPtFrameInfo( const SBrkPtInfo & vrBrkPtInfo, CMICmnMIValueTuple & vwrMiValueTuple );
+ bool MIResponseFormBrkPtInfo( const SBrkPtInfo & vrBrkPtInfo, CMICmnMIValueTuple & vwrMiValueTuple );
+ bool GetBrkPtInfo( const lldb::SBBreakpoint & vBrkPt, SBrkPtInfo & vrwBrkPtInfo ) const;
+ bool RecordBrkPtInfo( const MIuint vnBrkPtId, const SBrkPtInfo & vrBrkPtInfo );
+ bool RecordBrkPtInfoGet( const MIuint vnBrkPtId, SBrkPtInfo & vrwBrkPtInfo ) const;
+ bool RecordBrkPtInfoDelete( const MIuint vnBrkPtId );
+
+// Attributes:
+public:
+ // The following are available to all command instances
+ lldb::SBDebugger & m_rLldbDebugger;
+ lldb::SBListener & m_rLlldbListener;
+ lldb::SBTarget m_lldbTarget;
+ lldb::SBProcess m_lldbProcess;
+ const MIuint m_nBrkPointCntMax;
+ VecActiveThreadId_t m_vecActiveThreadId;
+ lldb::tid_t m_currentSelectedThread;
+
+ // These are keys that can be used to access the shared data map
+ // Note: This list is expected to grow and will be moved and abstracted in the future.
+ const CMIUtilString m_constStrSharedDataKeyWkDir;
+ const CMIUtilString m_constStrSharedDataSolibPath;
+
+// Typedefs:
+private:
+ typedef std::vector< CMICmnLLDBDebugSessionInfoVarObj > VecVarObj_t;
+ typedef std::map< MIuint, SBrkPtInfo > MapBrkPtIdToBrkPtInfo_t;
+ typedef std::pair< MIuint, SBrkPtInfo > MapPairBrkPtIdToBrkPtInfo_t;
+
+// Methods:
+private:
+ /* ctor */ CMICmnLLDBDebugSessionInfo( void );
+ /* ctor */ CMICmnLLDBDebugSessionInfo( const CMICmnLLDBDebugSessionInfo & );
+ void operator=( const CMICmnLLDBDebugSessionInfo & );
+ //
+ bool GetVariableInfo( const MIuint vnMaxDepth, const lldb::SBValue & vrValue, const bool vbIsChildValue, CMICmnMIValueList & vwrMiValueList, MIuint & vrwnDepth );
+ bool GetVariableInfo2( const MIuint vnMaxDepth, const lldb::SBValue & vrValue, const bool vbIsChildValue, CMICmnMIValueList & vwrMiValueList, MIuint & vrwnDepth );
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnLLDBDebugSessionInfo( void );
+
+// Attributes:
+private:
+ CMIUtilMapIdToVariant m_mapIdToSessionData; // Hold and retrieve key to value data available across all commands
+ VecVarObj_t m_vecVarObj; // Vector of session variable objects
+ MapBrkPtIdToBrkPtInfo_t m_mapBrkPtIdToBrkPtInfo;
+};
+
+//++ ------------------------------------------------------------------------------------
+// Details: Command instances can create and share data between other instances of commands.
+// This function adds new data to the shared data. Using the same ID more than
+// once replaces any previous matching data keys.
+// Type: Template method.
+// Args: T - The type of the object to be stored.
+// vKey - (R) A non empty unique data key to retrieve the data by.
+// vData - (R) Data to be added to the share.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+template< typename T >
+bool CMICmnLLDBDebugSessionInfo::SharedDataAdd( const CMIUtilString & vKey, const T & vData )
+{
+ if( !m_mapIdToSessionData.Add< T >( vKey, vData ) )
+ {
+ SetErrorDescription( m_mapIdToSessionData.GetErrorDescription() );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Command instances can create and share data between other instances of commands.
+// This function retrieves data from the shared data container.
+// Type: Method.
+// Args: T - The type of the object being retrieved.
+// vKey - (R) A non empty unique data key to retrieve the data by.
+// vData - (W) The data.
+// Return: bool - True = data found, false = data not found or an error occurred trying to fetch.
+// Throws: None.
+//--
+template< typename T >
+bool CMICmnLLDBDebugSessionInfo::SharedDataRetrieve( const CMIUtilString & vKey, T & vwData )
+{
+ bool bDataFound = false;
+
+ if( !m_mapIdToSessionData.Get< T >( vKey, vwData, bDataFound ) )
+ {
+ SetErrorDescription( m_mapIdToSessionData.GetErrorDescription() );
+ return MIstatus::failure;
+ }
+
+ return bDataFound;
+} \ No newline at end of file
diff --git a/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.cpp b/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.cpp
new file mode 100644
index 000000000000..d519875993fe
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.cpp
@@ -0,0 +1,570 @@
+//===-- MICmnLLDBDebugSessionInfoVarObj.cpp ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBDebugSessionInfoVarObj.cpp
+//
+// Overview: CMICmnLLDBDebugSessionInfoVarObj implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnLLDBDebugSessionInfoVarObj.h"
+#include "MICmnLLDBProxySBValue.h"
+#include "MICmnLLDBUtilSBValue.h"
+
+// Instantiations:
+const MIchar * CMICmnLLDBDebugSessionInfoVarObj::ms_aVarFormatStrings[] =
+{
+ // CODETAG_SESSIONINFO_VARFORMAT_ENUM
+ // *** Order is import here.
+ "<Invalid var format>",
+ "binary",
+ "octal",
+ "decimal",
+ "hexadecimal",
+ "natural"
+};
+const MIchar * CMICmnLLDBDebugSessionInfoVarObj::ms_aVarFormatChars[] =
+{
+ // CODETAG_SESSIONINFO_VARFORMAT_ENUM
+ // *** Order is import here.
+ "<Invalid var format>",
+ "t",
+ "o",
+ "d",
+ "x",
+ "N"
+};
+CMICmnLLDBDebugSessionInfoVarObj::MapKeyToVarObj_t CMICmnLLDBDebugSessionInfoVarObj::ms_mapVarIdToVarObj;
+MIuint CMICmnLLDBDebugSessionInfoVarObj::ms_nVarUniqueId = 0; // Index from 0
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebugSessionInfoVarObj constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfoVarObj::CMICmnLLDBDebugSessionInfoVarObj( void )
+: m_eVarFormat( eVarFormat_Natural )
+, m_eVarType( eVarType_Internal )
+{
+ // Do not call UpdateValue() in here as not necessary
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebugSessionInfoVarObj constructor.
+// Type: Method.
+// Args: vrStrNameReal - (R) The actual name of the variable, the expression.
+// vrStrName - (R) The name given for *this var object.
+// vrValue - (R) The LLDB SBValue object represented by *this object.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfoVarObj::CMICmnLLDBDebugSessionInfoVarObj( const CMIUtilString & vrStrNameReal, const CMIUtilString & vrStrName, const lldb::SBValue & vrValue )
+: m_eVarFormat( eVarFormat_Natural )
+, m_eVarType( eVarType_Internal )
+, m_strName( vrStrName )
+, m_SBValue( vrValue )
+, m_strNameReal( vrStrNameReal )
+{
+ UpdateValue();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebugSessionInfoVarObj constructor.
+// Type: Method.
+// Args: vrStrNameReal - (R) The actual name of the variable, the expression.
+// vrStrName - (R) The name given for *this var object.
+// vrValue - (R) The LLDB SBValue object represented by *this object.
+// vrStrVarObjParentName - (R) The var object parent to *this var object (LLDB SBValue equivalent).
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfoVarObj::CMICmnLLDBDebugSessionInfoVarObj( const CMIUtilString & vrStrNameReal, const CMIUtilString & vrStrName, const lldb::SBValue & vrValue, const CMIUtilString & vrStrVarObjParentName )
+: m_eVarFormat( eVarFormat_Natural )
+, m_eVarType( eVarType_Internal )
+, m_strName( vrStrName )
+, m_SBValue( vrValue )
+, m_strNameReal( vrStrNameReal )
+, m_strVarObjParentName( vrStrVarObjParentName )
+{
+ UpdateValue();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebugSessionInfoVarObj copy constructor.
+// Type: Method.
+// Args: vrOther - (R) The object to copy from.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfoVarObj::CMICmnLLDBDebugSessionInfoVarObj( const CMICmnLLDBDebugSessionInfoVarObj & vrOther )
+{
+ CopyOther( vrOther );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebugSessionInfoVarObj copy constructor.
+// Type: Method.
+// Args: vrOther - (R) The object to copy from.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfoVarObj::CMICmnLLDBDebugSessionInfoVarObj( CMICmnLLDBDebugSessionInfoVarObj & vrOther )
+{
+ CopyOther( vrOther );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebugSessionInfoVarObj move constructor.
+// Type: Method.
+// Args: vrwOther - (R) The object to copy from.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfoVarObj::CMICmnLLDBDebugSessionInfoVarObj( CMICmnLLDBDebugSessionInfoVarObj && vrwOther )
+{
+ MoveOther( vrwOther );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebugSessionInfoVarObj assignment operator.
+// Type: Method.
+// Args: vrOther - (R) The object to copy from.
+// Return: CMICmnLLDBDebugSessionInfoVarObj & - Updated *this object.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfoVarObj & CMICmnLLDBDebugSessionInfoVarObj::operator= ( const CMICmnLLDBDebugSessionInfoVarObj & vrOther )
+{
+ CopyOther( vrOther );
+
+ return *this;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebugSessionInfoVarObj assignment operator.
+// Type: Method.
+// Args: vrwOther - (R) The object to copy from.
+// Return: CMICmnLLDBDebugSessionInfoVarObj & - Updated *this object.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfoVarObj & CMICmnLLDBDebugSessionInfoVarObj::operator= ( CMICmnLLDBDebugSessionInfoVarObj && vrwOther )
+{
+ MoveOther( vrwOther );
+
+ return *this;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Copy the other instance of that object to *this object.
+// Type: Method.
+// Args: vrOther - (R) The object to copy from.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfoVarObj::CopyOther( const CMICmnLLDBDebugSessionInfoVarObj & vrOther )
+{
+ // Check for self-assignment
+ if( this == &vrOther )
+ return MIstatus::success;
+
+ m_eVarFormat = vrOther.m_eVarFormat;
+ m_eVarType = vrOther.m_eVarType;
+ m_strName = vrOther.m_strName;
+ m_SBValue = vrOther.m_SBValue;
+ m_strNameReal = vrOther.m_strNameReal;
+ m_strFormattedValue = vrOther.m_strFormattedValue;
+ m_strVarObjParentName = vrOther.m_strVarObjParentName;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Move that object to *this object.
+// Type: Method.
+// Args: vrwOther - (RW) The object to copy from.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfoVarObj::MoveOther( CMICmnLLDBDebugSessionInfoVarObj & vrwOther )
+{
+ // Check for self-assignment
+ if( this == &vrwOther )
+ return MIstatus::success;
+
+ CopyOther( vrwOther );
+ vrwOther.m_eVarFormat = eVarFormat_Natural;
+ vrwOther.m_eVarType = eVarType_Internal;
+ vrwOther.m_strName.clear();
+ vrwOther.m_SBValue.Clear();
+ vrwOther.m_strNameReal.clear();
+ vrwOther.m_strFormattedValue.clear();
+ vrwOther.m_strVarObjParentName.clear();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebugSessionInfoVarObj destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfoVarObj::~CMICmnLLDBDebugSessionInfoVarObj( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the var format enumeration for the specified string.
+// Type: Static method.
+// Args: vrStrFormat - (R) Text description of the var format.
+// Return: varFormat_e - Var format enumeration.
+// - No match found return eVarFormat_Invalid.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfoVarObj::varFormat_e CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForString( const CMIUtilString & vrStrFormat )
+{
+ // CODETAG_SESSIONINFO_VARFORMAT_ENUM
+ for( MIuint i = 0; i < eVarFormat_count; i++ )
+ {
+ const MIchar * pVarFormatString = ms_aVarFormatStrings[ i ];
+ if( vrStrFormat == pVarFormatString )
+ return static_cast< varFormat_e >( i );
+ }
+
+ return eVarFormat_Invalid;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the var format enumeration for the specified character.
+// Type: Static method.
+// Args: vrcFormat - (R) Character representing the var format.
+// Return: varFormat_e - Var format enumeration.
+// - No match found return eVarFormat_Invalid.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfoVarObj::varFormat_e CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForChar( const MIchar & vrcFormat )
+{
+ if( 'r' == vrcFormat )
+ return eVarFormat_Hex;
+
+ // CODETAG_SESSIONINFO_VARFORMAT_ENUM
+ for( MIuint i = 0; i < eVarFormat_count; i++ )
+ {
+ const MIchar * pVarFormatChar = ms_aVarFormatChars[ i ];
+ if( *pVarFormatChar == vrcFormat )
+ return static_cast< varFormat_e >( i );
+ }
+
+ return eVarFormat_Invalid;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Return the equivalent var value formatted string for the given value type.
+// The SBValue vrValue parameter is checked by LLDB private code for valid
+// scalar type via MI Driver proxy function as the valued returned can also be
+// an error condition. The proxy function determines if the check was valid
+// otherwise return an error condition state by other means saying so.
+// Type: Static method.
+// Args: vrValue - (R) The var value object.
+// veVarFormat - (R) Var format enumeration.
+// Returns: CMIUtilString - Value formatted string.
+// Throws: None.
+//--
+CMIUtilString CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted( const lldb::SBValue & vrValue, const CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veVarFormat )
+{
+ CMIUtilString strFormattedValue;
+
+ MIuint64 nValue = 0;
+ if( CMICmnLLDBProxySBValue::GetValueAsUnsigned( vrValue, nValue ) == MIstatus::success )
+ {
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( vrValue );
+ strFormattedValue = GetStringFormatted( nValue, rValue.GetValue(), veVarFormat );
+ }
+ else
+ {
+ // Composite variable type i.e. struct
+ strFormattedValue = "{...}";
+ }
+
+ return strFormattedValue;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Return nuber formatted string according to the given value type.
+// Type: Static method.
+// Args: vnValue - (R) The number value to get formatted.
+// vpStrValueNatural - (R) The natural representation of the number value.
+// veVarFormat - (R) Var format enumeration.
+// Returns: CMIUtilString - Numerical formatted string.
+// Throws: None.
+//--
+CMIUtilString CMICmnLLDBDebugSessionInfoVarObj::GetStringFormatted( const MIuint64 vnValue, const MIchar * vpStrValueNatural, const CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veVarFormat )
+{
+ CMIUtilString strFormattedValue;
+
+ switch( veVarFormat )
+ {
+ case eVarFormat_Binary:
+ strFormattedValue = CMIUtilString::FormatBinary( vnValue );
+ break;
+ case eVarFormat_Octal:
+ strFormattedValue = CMIUtilString::Format( "0%llo", vnValue );
+ break;
+ case eVarFormat_Decimal:
+ strFormattedValue = CMIUtilString::Format( "%lld", vnValue );
+ break;
+ case eVarFormat_Hex:
+ strFormattedValue = CMIUtilString::Format( "0x%llx", vnValue );
+ break;
+ case eVarFormat_Natural:
+ default:
+ {
+ strFormattedValue = (vpStrValueNatural != nullptr) ? vpStrValueNatural : "";
+ }
+ }
+
+ return strFormattedValue;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Delete internal container contents.
+// Type: Static method.
+// Args: None.
+// Returns: None.
+// Throws: None.
+//--
+void CMICmnLLDBDebugSessionInfoVarObj::VarObjClear( void )
+{
+ ms_mapVarIdToVarObj.clear();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add a var object to the internal container.
+// Type: Static method.
+// Args: vrVarObj - (R) The var value object.
+// Returns: None.
+// Throws: None.
+//--
+void CMICmnLLDBDebugSessionInfoVarObj::VarObjAdd( const CMICmnLLDBDebugSessionInfoVarObj & vrVarObj )
+{
+ VarObjDelete( vrVarObj.GetName() );
+ MapPairKeyToVarObj_t pr( vrVarObj.GetName(), vrVarObj );
+ ms_mapVarIdToVarObj.insert( pr );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Delete the var object from the internal container matching the specified name.
+// Type: Static method.
+// Args: vrVarName - (R) The var value name.
+// Returns: None.
+// Throws: None.
+//--
+void CMICmnLLDBDebugSessionInfoVarObj::VarObjDelete( const CMIUtilString & vrVarName )
+{
+ const MapKeyToVarObj_t::const_iterator it = ms_mapVarIdToVarObj.find( vrVarName );
+ if( it != ms_mapVarIdToVarObj.end() )
+ {
+ ms_mapVarIdToVarObj.erase( it );
+ }
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Update an existing var object in the internal container.
+// Type: Static method.
+// Args: vrVarObj - (R) The var value object.
+// Returns: None.
+// Throws: None.
+//--
+void CMICmnLLDBDebugSessionInfoVarObj::VarObjUpdate( const CMICmnLLDBDebugSessionInfoVarObj & vrVarObj )
+{
+ VarObjAdd( vrVarObj );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the var object matching the specified name.
+// Type: Static method.
+// Args: vrVarName - (R) The var value name.
+// vrwVarObj - (W) A var object.
+// Returns: bool - True = object found, false = object not found.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfoVarObj::VarObjGet( const CMIUtilString & vrVarName, CMICmnLLDBDebugSessionInfoVarObj & vrwVarObj )
+{
+ const MapKeyToVarObj_t::const_iterator it = ms_mapVarIdToVarObj.find( vrVarName );
+ if( it != ms_mapVarIdToVarObj.end() )
+ {
+ const CMICmnLLDBDebugSessionInfoVarObj & rVarObj = (*it).second;
+ vrwVarObj = rVarObj;
+ return true;
+ }
+
+ return false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: A count is kept of the number of var value objects created. This is count is
+// used to ID the var value object. Reset the count to 0.
+// Type: Static method.
+// Args: None.
+// Returns: None.
+// Throws: None.
+//--
+void CMICmnLLDBDebugSessionInfoVarObj::VarObjIdResetToZero( void )
+{
+ ms_nVarUniqueId = 0;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: A count is kept of the number of var value objects created. This is count is
+// used to ID the var value object. Increment the count by 1.
+// Type: Static method.
+// Args: None.
+// Returns: None.
+// Throws: None.
+//--
+void CMICmnLLDBDebugSessionInfoVarObj::VarObjIdInc( void )
+{
+ ms_nVarUniqueId++;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: A count is kept of the number of var value objects created. This is count is
+// used to ID the var value object. Retrieve ID.
+// Type: Static method.
+// Args: None.
+// Returns: None.
+// Throws: None.
+//--
+MIuint CMICmnLLDBDebugSessionInfoVarObj::VarObjIdGet( void )
+{
+ return ms_nVarUniqueId;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the value formatted object's name.
+// Type: Method.
+// Args: None.
+// Returns: CMIUtilString & - Value's var%u name text.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnLLDBDebugSessionInfoVarObj::GetName( void ) const
+{
+ return m_strName;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the value formatted object's variable name as given in the MI command
+// to create the var object.
+// Type: Method.
+// Args: None.
+// Returns: CMIUtilString & - Value's real name text.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnLLDBDebugSessionInfoVarObj::GetNameReal( void ) const
+{
+ return m_strNameReal;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the value formatted string.
+// Type: Method.
+// Args: None.
+// Returns: CMIUtilString & - Value formatted string.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnLLDBDebugSessionInfoVarObj::GetValueFormatted( void ) const
+{
+ return m_strFormattedValue;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the LLDB Value object.
+// Type: Method.
+// Args: None.
+// Returns: lldb::SBValue & - LLDB Value object.
+// Throws: None.
+//--
+const lldb::SBValue & CMICmnLLDBDebugSessionInfoVarObj::GetValue( void ) const
+{
+ return m_SBValue;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set the var format type for *this object and upate the formatting.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugSessionInfoVarObj::SetVarFormat( const varFormat_e veVarFormat )
+{
+ if( veVarFormat >= eVarFormat_count )
+ return MIstatus::failure;
+
+ m_eVarFormat = veVarFormat;
+ UpdateValue();
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Update *this var obj. Update it's value and type.
+// Type: Method.
+// Args: None.
+// Returns: None.
+// Throws: None.
+//--
+void CMICmnLLDBDebugSessionInfoVarObj::UpdateValue( void )
+{
+ m_strFormattedValue = CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted( m_SBValue, m_eVarFormat );
+
+ MIuint64 nValue = 0;
+ if( CMICmnLLDBProxySBValue::GetValueAsUnsigned( m_SBValue, nValue ) == MIstatus::failure )
+ m_eVarType = eVarType_Composite;
+
+ CMICmnLLDBDebugSessionInfoVarObj::VarObjUpdate( *this );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the enumeration type of the var object.
+// Type: Method.
+// Args: None.
+// Returns: varType_e - Enumeration value.
+// Throws: None.
+//--
+CMICmnLLDBDebugSessionInfoVarObj::varType_e CMICmnLLDBDebugSessionInfoVarObj::GetType( void ) const
+{
+ return m_eVarType;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the parent var object's name, the parent var object to *this var
+// object (if assigned). The parent is equivalent to LLDB SBValue variable's
+// parent.
+// Type: Method.
+// Args: None.
+// Returns: CMIUtilString & - Pointer to var object, NULL = no parent.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnLLDBDebugSessionInfoVarObj::GetVarParentName( void ) const
+{
+ return m_strVarObjParentName;
+}
+ \ No newline at end of file
diff --git a/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.h b/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.h
new file mode 100644
index 000000000000..1db7bd8daa05
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.h
@@ -0,0 +1,139 @@
+//===-- MICmnLLDBDebugSessionInfoVarObj.h -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBDebugSessionInfoVarObj.h
+//
+// Overview: CMICmnLLDBDebugSessionInfoVarObj interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third Party Headers:
+#include <map>
+#include <lldb/API/SBValue.h>
+
+// In-house headers:
+#include "MIUtilString.h"
+
+//++ ============================================================================
+// Details: MI debug session variable object. The static functionality in *this
+// class manages a map container of *these variable objects.
+// Gotchas: None.
+// Authors: Illya Rudkin 24/03/2014.
+// Changes: None.
+//--
+class CMICmnLLDBDebugSessionInfoVarObj
+{
+// Enums:
+public:
+ //++ ----------------------------------------------------------------------
+ // Details: Enumeration of a variable type that is not a composite type
+ //--
+ enum varFormat_e
+ {
+ // CODETAG_SESSIONINFO_VARFORMAT_ENUM
+ // *** Order is import here ***
+ eVarFormat_Invalid = 0,
+ eVarFormat_Binary,
+ eVarFormat_Octal,
+ eVarFormat_Decimal,
+ eVarFormat_Hex,
+ eVarFormat_Natural,
+ eVarFormat_count // Always last one
+ };
+
+ //++ ----------------------------------------------------------------------
+ // Details: Enumeration of a variable type by composite or internal type
+ //--
+ enum varType_e
+ {
+ eVarType_InValid = 0,
+ eVarType_Composite, // i.e. struct
+ eVarType_Internal, // i.e. int
+ eVarType_count // Always last one
+ };
+
+// Statics:
+public:
+ static varFormat_e GetVarFormatForString( const CMIUtilString & vrStrFormat );
+ static varFormat_e GetVarFormatForChar( const MIchar & vrcFormat );
+ static CMIUtilString GetValueStringFormatted( const lldb::SBValue & vrValue, const varFormat_e veVarFormat );
+ static void VarObjAdd( const CMICmnLLDBDebugSessionInfoVarObj & vrVarObj );
+ static void VarObjDelete( const CMIUtilString & vrVarName );
+ static bool VarObjGet( const CMIUtilString & vrVarName, CMICmnLLDBDebugSessionInfoVarObj & vrwVarObj );
+ static void VarObjUpdate( const CMICmnLLDBDebugSessionInfoVarObj & vrVarObj );
+ static void VarObjIdInc( void );
+ static MIuint VarObjIdGet( void );
+ static void VarObjIdResetToZero( void );
+ static void VarObjClear( void );
+
+// Methods:
+public:
+ /* ctor */ CMICmnLLDBDebugSessionInfoVarObj( void );
+ /* ctor */ CMICmnLLDBDebugSessionInfoVarObj( const CMIUtilString & vrStrNameReal, const CMIUtilString & vrStrName, const lldb::SBValue & vrValue );
+ /* ctor */ CMICmnLLDBDebugSessionInfoVarObj( const CMIUtilString & vrStrNameReal, const CMIUtilString & vrStrName, const lldb::SBValue & vrValue, const CMIUtilString & vrStrVarObjParentName );
+ /* ctor */ CMICmnLLDBDebugSessionInfoVarObj( const CMICmnLLDBDebugSessionInfoVarObj & vrOther );
+ /* ctor */ CMICmnLLDBDebugSessionInfoVarObj( CMICmnLLDBDebugSessionInfoVarObj & vrOther );
+ /* ctor */ CMICmnLLDBDebugSessionInfoVarObj( CMICmnLLDBDebugSessionInfoVarObj && vrOther );
+ //
+ CMICmnLLDBDebugSessionInfoVarObj & operator= ( const CMICmnLLDBDebugSessionInfoVarObj & vrOther );
+ CMICmnLLDBDebugSessionInfoVarObj & operator= ( CMICmnLLDBDebugSessionInfoVarObj && vrwOther );
+ //
+ const CMIUtilString & GetName( void ) const;
+ const CMIUtilString & GetNameReal( void ) const;
+ const CMIUtilString & GetValueFormatted( void ) const;
+ const lldb::SBValue & GetValue( void ) const;
+ varType_e GetType( void ) const;
+ bool SetVarFormat( const varFormat_e veVarFormat );
+ const CMIUtilString & GetVarParentName( void ) const;
+ void UpdateValue( void );
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnLLDBDebugSessionInfoVarObj( void );
+
+// Typedefs:
+private:
+ typedef std::map< CMIUtilString, CMICmnLLDBDebugSessionInfoVarObj > MapKeyToVarObj_t;
+ typedef std::pair< CMIUtilString, CMICmnLLDBDebugSessionInfoVarObj > MapPairKeyToVarObj_t;
+
+// Statics:
+private:
+ static CMIUtilString GetStringFormatted( const MIuint64 vnValue, const MIchar * vpStrValueNatural, varFormat_e veVarFormat );
+
+// Methods:
+private:
+ bool CopyOther( const CMICmnLLDBDebugSessionInfoVarObj & vrOther );
+ bool MoveOther( CMICmnLLDBDebugSessionInfoVarObj & vrwOther );
+
+// Attributes:
+private:
+ static const MIchar * ms_aVarFormatStrings[];
+ static const MIchar * ms_aVarFormatChars[];
+ static MapKeyToVarObj_t ms_mapVarIdToVarObj;
+ static MIuint ms_nVarUniqueId;
+ //
+ // *** Upate the copy move constructors and assignment operator ***
+ varFormat_e m_eVarFormat;
+ varType_e m_eVarType;
+ CMIUtilString m_strName;
+ lldb::SBValue m_SBValue;
+ CMIUtilString m_strNameReal;
+ CMIUtilString m_strFormattedValue;
+ CMIUtilString m_strVarObjParentName;
+ // *** Upate the copy move constructors and assignment operator ***
+};
diff --git a/tools/lldb-mi/MICmnLLDBDebugger.cpp b/tools/lldb-mi/MICmnLLDBDebugger.cpp
new file mode 100644
index 000000000000..f68f5083054b
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBDebugger.cpp
@@ -0,0 +1,707 @@
+//===-- MICmnLLDBDebugger.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBDebugger.cpp
+//
+// Overview: CMICmnLLDBDebugger implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third party headers:
+#include <lldb/API/SBTarget.h>
+#include <lldb/API/SBThread.h>
+#include <lldb/API/SBProcess.h>
+#include <lldb/API/SBCommandInterpreter.h>
+
+// In-house headers:
+#include "MICmnLLDBDebugger.h"
+#include "MICmnResources.h"
+#include "MICmnLog.h"
+#include "MIDriverBase.h"
+#include "MICmnThreadMgrStd.h"
+#include "MICmnLLDBDebuggerHandleEvents.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MIUtilSingletonHelper.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebugger constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBDebugger::CMICmnLLDBDebugger( void )
+: m_constStrThisThreadId( "MI debugger event" )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebugger destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBDebugger::~CMICmnLLDBDebugger( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this debugger object.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+ ClrErrorDescription();
+
+ if( m_pClientDriver == nullptr )
+ {
+ bOk = false;
+ errMsg = MIRSRC( IDS_LLDBDEBUGGER_ERR_CLIENTDRIVER );
+ }
+
+ // Note initialization order is important here as some resources depend on previous
+ MI::ModuleInit< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
+ MI::ModuleInit< CMICmnResources > ( IDS_MI_INIT_ERR_RESOURCES , bOk, errMsg );
+ MI::ModuleInit< CMICmnThreadMgrStd > ( IDS_MI_INIT_ERR_THREADMGR , bOk, errMsg );
+ MI::ModuleInit< CMICmnLLDBDebuggerHandleEvents >( IDS_MI_INIT_ERR_OUTOFBANDHANDLER, bOk, errMsg );
+ MI::ModuleInit< CMICmnLLDBDebugSessionInfo > ( IDS_MI_INIT_ERR_DEBUGSESSIONINFO, bOk, errMsg );
+
+ // Note order is important here!
+ if( bOk )
+ lldb::SBDebugger::Initialize();
+ if( bOk && !InitSBDebugger() )
+ {
+ bOk = false;
+ if( !errMsg.empty() ) errMsg += ", ";
+ errMsg += GetErrorDescription().c_str();
+ }
+ if( bOk && !InitSBListener() )
+ {
+ bOk = false;
+ if( !errMsg.empty() ) errMsg += ", ";
+ errMsg += GetErrorDescription().c_str();
+ }
+ bOk = bOk && InitStdStreams();
+
+ m_bInitialized = bOk;
+
+ if( !bOk && !HaveErrorDescription() )
+ {
+ CMIUtilString strInitError( CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_LLDBDEBUGGER ), errMsg.c_str() ) );
+ SetErrorDescription( strInitError );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this debugger object.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = false;
+
+ ClrErrorDescription();
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Explicitly delete the remote target in case MI needs to exit prematurely otherwise
+ // LLDB debugger may hang in its Destroy() fn waiting on events
+ m_lldbDebugger.DeleteTarget( CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget );
+
+ // Debug: May need this but does seem to work without it so commented out the fudge 19/06/2014
+ // It appears we need to wait as hang does not occur when hitting a debug breakpoint here
+ //const std::chrono::milliseconds time( 1000 );
+ //std::this_thread::sleep_for( time );
+
+ lldb::SBDebugger::Destroy( m_lldbDebugger );
+ lldb::SBDebugger::Terminate();
+ m_pClientDriver = nullptr;
+ m_mapBroadcastClassNameToEventMask.clear();
+ m_mapIdToEventMask.clear();
+
+ // Note shutdown order is important here
+ MI::ModuleShutdown< CMICmnLLDBDebugSessionInfo > ( IDS_MI_INIT_ERR_DEBUGSESSIONINFO, bOk, errMsg );
+ MI::ModuleShutdown< CMICmnLLDBDebuggerHandleEvents >( IDS_MI_INIT_ERR_OUTOFBANDHANDLER, bOk, errMsg );
+ MI::ModuleShutdown< CMICmnThreadMgrStd > ( IDS_MI_INIT_ERR_THREADMGR , bOk, errMsg );
+ MI::ModuleShutdown< CMICmnResources > ( IDS_MI_INIT_ERR_RESOURCES , bOk, errMsg );
+ MI::ModuleShutdown< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
+
+ if( !bOk )
+ {
+ SetErrorDescriptionn( MIRSRC( IDS_MI_SHTDWN_ERR_LLDBDEBUGGER ), errMsg.c_str() );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Return the LLDB debugger instance created for this debug session.
+// Type: Method.
+// Args: None.
+// Return: lldb::SBDebugger & - LLDB debugger object reference.
+// Throws: None.
+//--
+lldb::SBDebugger & CMICmnLLDBDebugger::GetTheDebugger( void )
+{
+ return m_lldbDebugger;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Return the LLDB listener instance created for this debug session.
+// Type: Method.
+// Args: None.
+// Return: lldb::SBListener & - LLDB listener object reference.
+// Throws: None.
+//--
+lldb::SBListener & CMICmnLLDBDebugger::GetTheListener( void )
+{
+ return m_lldbListener;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set the client driver that wants to use *this LLDB debugger. Call this function
+// prior to Initialize().
+// Type: Method.
+// Args: vClientDriver - (R) A driver.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::SetDriver( const CMIDriverBase & vClientDriver )
+{
+ m_pClientDriver = const_cast< CMIDriverBase * >( &vClientDriver );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get the client driver that is use *this LLDB debugger.
+// Type: Method.
+// Args: vClientDriver - (R) A driver.
+// Return: CMIDriverBase & - A driver instance.
+// Throws: None.
+//--
+CMIDriverBase & CMICmnLLDBDebugger::GetDriver( void ) const
+{
+ return *m_pClientDriver;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize the LLDB Debugger object.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::InitSBDebugger( void )
+{
+ m_lldbDebugger = lldb::SBDebugger::Create( false );
+ if( m_lldbDebugger.IsValid() )
+ return MIstatus::success;
+
+ SetErrorDescription( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDDEBUGGER ) );
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set the LLDB Debugger's std in, err and out streams. (Not implemented left
+// here for reference. Was called in the CMICmnLLDBDebugger::Initialize() )
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::InitStdStreams( void )
+{
+ // This is not required when operating the MI driver's code as it has its own
+ // streams. Setting the Stdin for the lldbDebugger especially on LINUX will cause
+ // another thread to run and partially consume stdin data meant for MI stdin handler
+ //m_lldbDebugger.SetErrorFileHandle( m_pClientDriver->GetStderr(), false );
+ //m_lldbDebugger.SetOutputFileHandle( m_pClientDriver->GetStdout(), false );
+ //m_lldbDebugger.SetInputFileHandle( m_pClientDriver->GetStdin(), false );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set up the events from the SBDebugger's we would to listent to.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::InitSBListener( void )
+{
+ m_lldbListener = m_lldbDebugger.GetListener();
+ if( !m_lldbListener.IsValid() )
+ {
+ SetErrorDescription( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDLISTENER ) );
+ return MIstatus::failure;
+ }
+
+ const CMIUtilString strDbgId( "CMICmnLLDBDebugger1" );
+ MIuint eventMask = lldb::SBTarget::eBroadcastBitBreakpointChanged;
+ bool bOk = RegisterForEvent( strDbgId, CMIUtilString( lldb::SBTarget::GetBroadcasterClassName() ), eventMask );
+
+ eventMask = lldb::SBThread::eBroadcastBitStackChanged;
+ bOk = bOk && RegisterForEvent( strDbgId, CMIUtilString( lldb::SBThread::GetBroadcasterClassName() ), eventMask );
+
+ eventMask = lldb::SBProcess::eBroadcastBitStateChanged |
+ lldb::SBProcess::eBroadcastBitInterrupt |
+ lldb::SBProcess::eBroadcastBitSTDOUT |
+ lldb::SBProcess::eBroadcastBitSTDERR |
+ lldb::SBProcess::eBroadcastBitProfileData;
+ bOk = bOk && RegisterForEvent( strDbgId, CMIUtilString( lldb::SBProcess::GetBroadcasterClassName() ), eventMask );
+
+ eventMask = lldb::SBCommandInterpreter::eBroadcastBitQuitCommandReceived |
+ lldb::SBCommandInterpreter::eBroadcastBitThreadShouldExit |
+ lldb::SBCommandInterpreter::eBroadcastBitAsynchronousOutputData |
+ lldb::SBCommandInterpreter::eBroadcastBitAsynchronousErrorData;
+ bOk = bOk && RegisterForEvent( strDbgId, CMIUtilString( lldb::SBCommandInterpreter::GetBroadcasterClass() ), eventMask );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Register with the debugger, the SBListener, the type of events you are interested
+// in. Others, like commands, may have already set the mask.
+// Type: Method.
+// Args: vClientName - (R) ID of the client who wants these events set.
+// vBroadcasterClass - (R) The SBBroadcaster's class name.
+// vEventMask - (R) The mask of events to listen for.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::RegisterForEvent( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass, const MIuint vEventMask )
+{
+ MIuint existingMask = 0;
+ if( !BroadcasterGetMask( vBroadcasterClass, existingMask ) )
+ return MIstatus::failure;
+
+ if( !ClientSaveMask( vClientName, vBroadcasterClass, vEventMask ) )
+ return MIstatus::failure;
+
+ const MIchar * pBroadCasterName = vBroadcasterClass.c_str();
+ MIuint eventMask = vEventMask;
+ eventMask += existingMask;
+ const MIuint result = m_lldbListener.StartListeningForEventClass( m_lldbDebugger, pBroadCasterName, eventMask );
+ if( result == 0 )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_STARTLISTENER ), pBroadCasterName ) );
+ return MIstatus::failure;
+ }
+
+ return BroadcasterSaveMask( vBroadcasterClass, eventMask );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Register with the debugger, the SBListener, the type of events you are interested
+// in. Others, like commands, may have already set the mask.
+// Type: Method.
+// Args: vClientName - (R) ID of the client who wants these events set.
+// vBroadcaster - (R) An SBBroadcaster's derived class.
+// vEventMask - (R) The mask of events to listen for.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::RegisterForEvent( const CMIUtilString & vClientName, const lldb::SBBroadcaster & vBroadcaster, const MIuint vEventMask )
+{
+ const MIchar * pBroadcasterName = vBroadcaster.GetName();
+ if( pBroadcasterName == nullptr )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_BROARDCASTER_NAME ), MIRSRC( IDS_WORD_INVALIDNULLPTR ) ) );
+ return MIstatus::failure;
+ }
+ CMIUtilString broadcasterName( pBroadcasterName );
+ if( broadcasterName.length() == 0 )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_BROARDCASTER_NAME ), MIRSRC( IDS_WORD_INVALIDEMPTY ) ) );
+ return MIstatus::failure;
+ }
+
+ MIuint existingMask = 0;
+ if( !BroadcasterGetMask( broadcasterName, existingMask ) )
+ return MIstatus::failure;
+
+ if( !ClientSaveMask( vClientName, broadcasterName, vEventMask ) )
+ return MIstatus::failure;
+
+ MIuint eventMask = vEventMask;
+ eventMask += existingMask;
+ const MIuint result = m_lldbListener.StartListeningForEvents( vBroadcaster, eventMask );
+ if( result == 0 )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_STARTLISTENER ), pBroadcasterName ) );
+ return MIstatus::failure;
+ }
+
+ return BroadcasterSaveMask( broadcasterName, eventMask );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Unregister with the debugger, the SBListener, the type of events you are no
+// longer interested in. Others, like commands, may still remain interested so
+// an event may not necessarily be stopped.
+// Type: Method.
+// Args: vClientName - (R) ID of the client who no longer requires these events.
+// vBroadcasterClass - (R) The SBBroadcaster's class name.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::UnregisterForEvent( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass )
+{
+ MIuint clientsEventMask = 0;
+ if( !ClientGetTheirMask( vClientName, vBroadcasterClass, clientsEventMask ) )
+ return MIstatus::failure;
+ if( !ClientRemoveTheirMask( vClientName, vBroadcasterClass ) )
+ return MIstatus::failure;
+
+ const MIuint otherClientsEventMask = ClientGetMaskForAllClients( vBroadcasterClass );
+ MIuint newEventMask = 0;
+ for( MIuint i = 0; i < 32; i++ )
+ {
+ const MIuint bit = 1 << i;
+ const MIuint clientBit = bit & clientsEventMask;
+ const MIuint othersBit = bit & otherClientsEventMask;
+ if( (clientBit != 0) && (othersBit == 0) )
+ {
+ newEventMask += clientBit;
+ }
+ }
+
+ const MIchar * pBroadCasterName = vBroadcasterClass.c_str();
+ if( !m_lldbListener.StopListeningForEventClass( m_lldbDebugger, pBroadCasterName, newEventMask ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_STOPLISTENER ), vClientName.c_str(), pBroadCasterName ) );
+ return MIstatus::failure;
+ }
+
+ return BroadcasterSaveMask( vBroadcasterClass, otherClientsEventMask );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Given the SBBroadcaster class name retrieve it's current event mask.
+// Type: Method.
+// Args: vBroadcasterClass - (R) The SBBroadcaster's class name.
+// vEventMask - (W) The mask of events to listen for.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::BroadcasterGetMask( const CMIUtilString & vBroadcasterClass, MIuint & vwEventMask ) const
+{
+ vwEventMask = 0;
+
+ if( vBroadcasterClass.empty() )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDBROADCASTER ), vBroadcasterClass.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ const MapBroadcastClassNameToEventMask_t::const_iterator it = m_mapBroadcastClassNameToEventMask.find( vBroadcasterClass );
+ if( it != m_mapBroadcastClassNameToEventMask.end() )
+ {
+ vwEventMask = (*it).second;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Remove the event mask for the specified SBBroadcaster class name.
+// Type: Method.
+// Args: vBroadcasterClass - (R) The SBBroadcaster's class name.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::BroadcasterRemoveMask( const CMIUtilString & vBroadcasterClass )
+{
+ MapBroadcastClassNameToEventMask_t::const_iterator it = m_mapBroadcastClassNameToEventMask.find( vBroadcasterClass );
+ if( it != m_mapBroadcastClassNameToEventMask.end() )
+ {
+ m_mapBroadcastClassNameToEventMask.erase( it );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Given the SBBroadcaster class name save it's current event mask.
+// Type: Method.
+// Args: vBroadcasterClass - (R) The SBBroadcaster's class name.
+// vEventMask - (R) The mask of events to listen for.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::BroadcasterSaveMask( const CMIUtilString & vBroadcasterClass, const MIuint vEventMask )
+{
+ if( vBroadcasterClass.empty() )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDBROADCASTER ), vBroadcasterClass.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ BroadcasterRemoveMask( vBroadcasterClass );
+ MapPairBroadcastClassNameToEventMask_t pr( vBroadcasterClass, vEventMask );
+ m_mapBroadcastClassNameToEventMask.insert( pr );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Iterate all the clients who have registered event masks against particular
+// SBBroadcasters and build up the mask that is for all of them.
+// Type: Method.
+// Args: vBroadcasterClass - (R) The broadcaster to retrieve the mask for.
+// Return: MIuint - Event mask.
+// Throws: None.
+//--
+MIuint CMICmnLLDBDebugger::ClientGetMaskForAllClients( const CMIUtilString & vBroadcasterClass ) const
+{
+ MIuint mask = 0;
+ MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.begin();
+ while( it != m_mapIdToEventMask.end() )
+ {
+ const CMIUtilString & rId( (*it).first );
+ if( rId.find( vBroadcasterClass.c_str() ) != std::string::npos )
+ {
+ const MIuint clientsMask = (*it).second;
+ mask |= clientsMask;
+ }
+
+ // Next
+ ++it;
+ }
+
+ return mask;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Given the client save its particular event requirements.
+// Type: Method.
+// Args: vClientName - (R) The Client's unique ID.
+// vBroadcasterClass - (R) The SBBroadcaster's class name targeted for the events.
+// vEventMask - (R) The mask of events to listen for.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::ClientSaveMask( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass, const MIuint vEventMask )
+{
+ if( vClientName.empty() )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME ), vClientName.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMIUtilString strId( vBroadcasterClass );
+ strId += vClientName;
+
+ ClientRemoveTheirMask( vClientName, vBroadcasterClass );
+ MapPairIdToEventMask_t pr( strId, vEventMask );
+ m_mapIdToEventMask.insert( pr );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Given the client remove it's particular event requirements.
+// Type: Method.
+// Args: vClientName - (R) The Client's unique ID.
+// vBroadcasterClass - (R) The SBBroadcaster's class name.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::ClientRemoveTheirMask( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass )
+{
+ if( vClientName.empty() )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME ), vClientName.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMIUtilString strId( vBroadcasterClass );
+ strId += vClientName;
+
+ const MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.find( strId );
+ if( it != m_mapIdToEventMask.end() )
+ {
+ m_mapIdToEventMask.erase( it );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the client's event mask used for on a particular SBBroadcaster.
+// Type: Method.
+// Args: vClientName - (R) The Client's unique ID.
+// vBroadcasterClass - (R) The SBBroadcaster's class name.
+// vwEventMask - (W) The client's mask.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::ClientGetTheirMask( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass, MIuint & vwEventMask )
+{
+ vwEventMask = 0;
+
+ if( vClientName.empty() )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME ), vClientName.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ CMIUtilString strId( vBroadcasterClass.c_str() );
+ strId += vClientName;
+
+ const MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.find( strId );
+ if( it != m_mapIdToEventMask.end() )
+ {
+ vwEventMask = (*it).second;
+ }
+
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_CLIENTNOTREGISTERD ), vClientName.c_str() ) );
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Momentarily wait for an events being broadcast and inspect those that do
+// come this way. Check if the target should exit event if so start shutting
+// down this thread and the application. Any other events pass on to the
+// Out-of-band handler to futher determine what kind of event arrived.
+// This function runs in the thread "MI debugger event".
+// Type: Method.
+// Args: vrbIsAlive - (W) False = yes exit event monitoring thread, true = continue.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::MonitorSBListenerEvents( bool & vrbIsAlive )
+{
+ vrbIsAlive = true;
+
+ lldb::SBEvent event;
+ const bool bGotEvent = m_lldbListener.GetNextEvent( event );
+ if ( !bGotEvent || !event.IsValid() )
+ {
+ const std::chrono::milliseconds time( 1 );
+ std::this_thread::sleep_for( time );
+ return MIstatus::success;
+ }
+ if( !event.GetBroadcaster().IsValid() )
+ return MIstatus::success;
+
+ // Debugging
+ m_pLog->WriteLog( CMIUtilString::Format( "##### An event occurred: %s", event.GetBroadcasterClass() ) );
+
+ bool bHandledEvent = false;
+ bool bExitAppEvent = false;
+ const bool bOk = CMICmnLLDBDebuggerHandleEvents::Instance().HandleEvent( event, bHandledEvent, bExitAppEvent );
+ if( !bHandledEvent )
+ {
+ const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_WRN_UNKNOWN_EVENT ), event.GetBroadcasterClass() ) );
+ m_pLog->WriteLog( msg );
+ }
+ if( !bOk )
+ {
+ m_pLog->WriteLog( CMICmnLLDBDebuggerHandleEvents::Instance().GetErrorDescription() );
+ }
+
+ if( bExitAppEvent )
+ {
+ // Set the application to shutdown
+ m_pClientDriver->SetExitApplicationFlag( true );
+
+ // Kill *this thread
+ vrbIsAlive = false;
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The main worker method for this thread.
+// Type: Method.
+// Args: vrbIsAlive = (W) True = *this thread is working, false = thread has exited.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::ThreadRun( bool & vrbIsAlive )
+{
+ return MonitorSBListenerEvents( vrbIsAlive );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Let this thread clean up after itself.
+// Type: Method.
+// Args:
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebugger::ThreadFinish( void )
+{
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve *this thread object's name.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString & - Text.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnLLDBDebugger::ThreadGetName( void ) const
+{
+ return m_constStrThisThreadId;
+}
diff --git a/tools/lldb-mi/MICmnLLDBDebugger.h b/tools/lldb-mi/MICmnLLDBDebugger.h
new file mode 100644
index 000000000000..0d608997d959
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBDebugger.h
@@ -0,0 +1,125 @@
+//===-- MICmnLLDBDebugger.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBDebugger.h
+//
+// Overview: CMICmnLLDBDebugger interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers
+#include <queue>
+#include <map>
+#include <lldb/API/SBDebugger.h>
+#include <lldb/API/SBListener.h>
+#include <lldb/API/SBEvent.h>
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MIUtilThreadBaseStd.h"
+#include "MIUtilSingletonBase.h"
+
+// Declarations:
+class CMIDriverBase;
+class CMICmnLLDBDebuggerHandleEvents;
+
+//++ ============================================================================
+// Details: MI proxy/adapter for the LLDB public SBDebugger API. The CMIDriver
+// requires *this object. Command classes make calls on *this object
+// to facilitate their work effort. The instance runs in its own worker
+// thread.
+// A singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 26/02/2014.
+// Changes: None.
+//--
+class CMICmnLLDBDebugger
+: public CMICmnBase
+, public CMIUtilThreadActiveObjBase
+, public MI::ISingleton< CMICmnLLDBDebugger >
+{
+ friend class MI::ISingleton< CMICmnLLDBDebugger >;
+
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+
+ bool SetDriver( const CMIDriverBase & vClientDriver );
+ CMIDriverBase & GetDriver( void ) const;
+ lldb::SBDebugger & GetTheDebugger( void );
+ lldb::SBListener & GetTheListener( void );
+
+ // MI Commands can use these functions to listen for events they require
+ bool RegisterForEvent( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass, const MIuint vEventMask );
+ bool UnregisterForEvent( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass );
+ bool RegisterForEvent( const CMIUtilString & vClientName, const lldb::SBBroadcaster & vBroadcaster, const MIuint vEventMask );
+ bool UnregisterForEvent( const CMIUtilString & vClientName, const lldb::SBBroadcaster & vBroadcaster );
+
+// Overridden:
+public:
+ // From CMIUtilThreadActiveObjBase
+ virtual const CMIUtilString & ThreadGetName( void ) const;
+
+// Overridden:
+protected:
+ // From CMIUtilThreadActiveObjBase
+ virtual bool ThreadRun( bool & vrIsAlive );
+ virtual bool ThreadFinish( void );
+
+// Typedefs:
+private:
+ typedef std::map< CMIUtilString, MIuint > MapBroadcastClassNameToEventMask_t;
+ typedef std::pair< CMIUtilString, MIuint > MapPairBroadcastClassNameToEventMask_t;
+ typedef std::map< CMIUtilString, MIuint > MapIdToEventMask_t;
+ typedef std::pair< CMIUtilString, MIuint > MapPairIdToEventMask_t;
+
+// Methods:
+private:
+ /* ctor */ CMICmnLLDBDebugger( void );
+ /* ctor */ CMICmnLLDBDebugger( const CMICmnLLDBDebugger & );
+ void operator=( const CMICmnLLDBDebugger & );
+
+ bool InitSBDebugger( void );
+ bool InitSBListener( void );
+ bool InitStdStreams( void );
+ bool MonitorSBListenerEvents( bool & vrbYesExit );
+
+ bool BroadcasterGetMask( const CMIUtilString & vBroadcasterClass, MIuint & vEventMask ) const;
+ bool BroadcasterRemoveMask( const CMIUtilString & vBroadcasterClass );
+ bool BroadcasterSaveMask( const CMIUtilString & vBroadcasterClass, const MIuint vEventMask );
+
+ MIuint ClientGetMaskForAllClients( const CMIUtilString & vBroadcasterClass ) const;
+ bool ClientSaveMask( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass, const MIuint vEventMask );
+ bool ClientRemoveTheirMask( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass );
+ bool ClientGetTheirMask( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass, MIuint & vwEventMask );
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnLLDBDebugger( void );
+
+// Attributes:
+private:
+ CMIDriverBase * m_pClientDriver; // The driver that wants to use *this LLDB debugger
+ lldb::SBDebugger m_lldbDebugger; // SBDebugger is the primordial object that creates SBTargets and provides access to them
+ lldb::SBListener m_lldbListener; // API clients can register its own listener to debugger events
+ const CMIUtilString m_constStrThisThreadId;
+ MapBroadcastClassNameToEventMask_t m_mapBroadcastClassNameToEventMask;
+ MapIdToEventMask_t m_mapIdToEventMask;
+};
+
diff --git a/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp b/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
new file mode 100644
index 000000000000..08218a2e87e4
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
@@ -0,0 +1,1566 @@
+//===-- MICmnLLDBDebuggerHandleEvents.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBDebuggerHandleEvents.cpp
+//
+// Overview: CMICmnLLDBDebuggerHandleEvents implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third party headers:
+#include <lldb/API/SBEvent.h>
+#include <lldb/API/SBProcess.h>
+#include <lldb/API/SBBreakpoint.h>
+#include <lldb/API/SBStream.h>
+#include <lldb/API/SBThread.h>
+#include <lldb/API/SBCommandInterpreter.h>
+#include <lldb/API/SBCommandReturnObject.h>
+#ifdef _WIN32
+ #include <io.h> // For the ::_access()
+#else
+ #include <unistd.h> // For the ::access()
+#endif // _WIN32
+#include <limits.h>
+
+// In-house headers:
+#include "MICmnLLDBDebuggerHandleEvents.h"
+#include "MICmnResources.h"
+#include "MICmnLog.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnMIValueList.h"
+#include "MICmnMIOutOfBandRecord.h"
+#include "MICmnStreamStdout.h"
+#include "MICmnStreamStderr.h"
+#include "MIUtilDebug.h"
+#include "MIDriver.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebuggerHandleEvents constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBDebuggerHandleEvents::CMICmnLLDBDebuggerHandleEvents( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBDebuggerHandleEvents destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBDebuggerHandleEvents::~CMICmnLLDBDebuggerHandleEvents( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this broardcaster object.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = MIstatus::success;
+
+ return m_bInitialized;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this broardcaster object.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = false;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Interpret the event object to asscertain the action to take or information to
+// to form and put in a MI Out-of-band record object which is given to stdout.
+// Type: Method.
+// Args: vEvent - (R) An LLDB broadcast event.
+// vrbHandledEvent - (W) True - event handled, false = not handled.
+// vrbExitAppEvent - (W) True - Received LLDB exit app event, false = did not.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleEvent( const lldb::SBEvent & vEvent, bool & vrbHandledEvent, bool & vrbExitAppEvent )
+{
+ bool bOk = MIstatus::success;
+ vrbHandledEvent = false;
+ vrbExitAppEvent = false;
+
+ if( lldb::SBProcess::EventIsProcessEvent( vEvent ) )
+ {
+ vrbHandledEvent = true;
+ bOk = HandleEventSBProcess( vEvent, vrbExitAppEvent );
+ }
+ else if( lldb::SBBreakpoint::EventIsBreakpointEvent( vEvent ) )
+ {
+ vrbHandledEvent = true;
+ bOk = HandleEventSBBreakPoint( vEvent );
+ }
+ else if( lldb::SBThread::EventIsThreadEvent( vEvent ) )
+ {
+ vrbHandledEvent = true;
+ bOk = HandleEventSBThread( vEvent );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Handle a LLDB SBProcess event.
+// Type: Method.
+// Args: vEvent - (R) An LLDB broadcast event.
+// vrbExitAppEvent - (W) True - Received LLDB exit app event, false = did not.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBProcess( const lldb::SBEvent & vEvent, bool & vrbExitAppEvent )
+{
+ bool bOk = MIstatus::success;
+
+ const MIchar * pEventType = "";
+ const MIuint nEventType = vEvent.GetType();
+ switch( nEventType )
+ {
+ case lldb::SBProcess::eBroadcastBitInterrupt:
+ pEventType = "eBroadcastBitInterrupt";
+ break;
+ case lldb::SBProcess::eBroadcastBitProfileData:
+ pEventType = "eBroadcastBitProfileData";
+ break;
+ case lldb::SBProcess::eBroadcastBitStateChanged:
+ pEventType = "eBroadcastBitStateChanged";
+ bOk = HandleProcessEventBroadcastBitStateChanged( vEvent, vrbExitAppEvent );
+ break;
+ case lldb::SBProcess::eBroadcastBitSTDERR:
+ pEventType = "eBroadcastBitSTDERR";
+ bOk = GetProcessStderr();
+ break;
+ case lldb::SBProcess::eBroadcastBitSTDOUT:
+ pEventType = "eBroadcastBitSTDOUT";
+ bOk = GetProcessStdout();
+ break;
+ default:
+ {
+ const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT ), "SBProcess", (MIuint) nEventType ) );
+ SetErrorDescription( msg );
+ return MIstatus::failure;
+ }
+ }
+ m_pLog->WriteLog( CMIUtilString::Format( "##### An SB Process event occurred: %s", pEventType ) );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Handle a LLDB SBBreakpoint event.
+// Type: Method.
+// Args: vEvent - (R) An LLDB broadcast event.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakPoint( const lldb::SBEvent & vEvent )
+{
+ bool bOk = MIstatus::success;
+
+ const MIchar * pEventType ="";
+ const lldb::BreakpointEventType eEvent = lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent( vEvent );
+ switch( eEvent )
+ {
+ case lldb::eBreakpointEventTypeThreadChanged:
+ pEventType = "eBreakpointEventTypeThreadChanged";
+ break;
+ case lldb::eBreakpointEventTypeLocationsRemoved:
+ pEventType = "eBreakpointEventTypeLocationsRemoved";
+ break;
+ case lldb::eBreakpointEventTypeInvalidType:
+ pEventType = "eBreakpointEventTypeInvalidType";
+ break;
+ case lldb::eBreakpointEventTypeLocationsAdded:
+ pEventType = "eBreakpointEventTypeLocationsAdded";
+ bOk = HandleEventSBBreakpointLocationsAdded( vEvent );
+ break;
+ case lldb::eBreakpointEventTypeAdded:
+ pEventType = "eBreakpointEventTypeAdded";
+ bOk = HandleEventSBBreakpointAdded( vEvent );
+ break;
+ case lldb::eBreakpointEventTypeRemoved:
+ pEventType = "eBreakpointEventTypeRemoved";
+ bOk = HandleEventSBBreakpointCmn( vEvent );
+ break;
+ case lldb::eBreakpointEventTypeLocationsResolved:
+ pEventType = "eBreakpointEventTypeLocationsResolved";
+ break;
+ case lldb::eBreakpointEventTypeEnabled:
+ pEventType ="eBreakpointEventTypeEnabled";
+ bOk = HandleEventSBBreakpointCmn( vEvent );
+ break;
+ case lldb::eBreakpointEventTypeDisabled:
+ pEventType = "eBreakpointEventTypeDisabled";
+ bOk = HandleEventSBBreakpointCmn( vEvent );
+ break;
+ case lldb::eBreakpointEventTypeCommandChanged:
+ pEventType = "eBreakpointEventTypeCommandChanged";
+ bOk = HandleEventSBBreakpointCmn( vEvent );
+ break;
+ case lldb::eBreakpointEventTypeConditionChanged:
+ pEventType ="eBreakpointEventTypeConditionChanged";
+ bOk = HandleEventSBBreakpointCmn( vEvent );
+ break;
+ case lldb::eBreakpointEventTypeIgnoreChanged:
+ pEventType = "eBreakpointEventTypeIgnoreChanged";
+ bOk = HandleEventSBBreakpointCmn( vEvent );
+ break;
+ default:
+ {
+ const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT ), "SBBreakPoint", (MIuint) eEvent ) );
+ SetErrorDescription( msg );
+ return MIstatus::failure;
+ }
+ }
+ m_pLog->WriteLog( CMIUtilString::Format( "##### An SB Breakpoint event occurred: %s", pEventType ) );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Handle a LLDB SBBreakpoint event.
+// Type: Method.
+// Args: vEvent - (R) An LLDB broadcast event.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakpointLocationsAdded( const lldb::SBEvent & vEvent )
+{
+ const MIuint nLoc = lldb::SBBreakpoint::GetNumBreakpointLocationsFromEvent( vEvent );
+ if( nLoc == 0 )
+ return MIstatus::success;
+
+ lldb::SBBreakpoint brkPt = lldb::SBBreakpoint::GetBreakpointFromEvent( vEvent );
+ const CMIUtilString plural( (nLoc == 1) ? "" : "s" );
+ const CMIUtilString msg( CMIUtilString::Format( "%d location%s added to breakpoint %d", nLoc, plural.c_str(), brkPt.GetID() ) );
+
+ return TextToStdout( msg );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Handle a LLDB SBBreakpoint event.
+// Type: Method.
+// Args: vEvent - (R) An LLDB broadcast event.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakpointCmn( const lldb::SBEvent & vEvent )
+{
+ lldb::SBBreakpoint brkPt = lldb::SBBreakpoint::GetBreakpointFromEvent( vEvent );
+ if( !brkPt.IsValid() )
+ return MIstatus::success;
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfo;
+ if( !rSessionInfo.GetBrkPtInfo( brkPt, sBrkPtInfo ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_BRKPT_INFO_GET ), "HandleEventSBBreakpointCmn()", brkPt.GetID() ) );
+ return MIstatus::failure;
+ }
+
+ // CODETAG_LLDB_BREAKPOINT_CREATION
+ // This is in a worker thread
+ // Add more breakpoint information or overwrite existing information
+ CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfoRec;
+ if( !rSessionInfo.RecordBrkPtInfoGet( brkPt.GetID(), sBrkPtInfoRec ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_BRKPT_NOTFOUND ), "HandleEventSBBreakpointCmn()", brkPt.GetID() ) );
+ return MIstatus::failure;
+ }
+ sBrkPtInfo.m_bDisp = sBrkPtInfoRec.m_bDisp;
+ sBrkPtInfo.m_bEnabled = brkPt.IsEnabled();
+ sBrkPtInfo.m_bHaveArgOptionThreadGrp = false;
+ sBrkPtInfo.m_strOptThrdGrp = "";
+ sBrkPtInfo.m_nTimes = brkPt.GetHitCount();
+ sBrkPtInfo.m_strOrigLoc = sBrkPtInfoRec.m_strOrigLoc;
+ sBrkPtInfo.m_nIgnore = sBrkPtInfoRec.m_nIgnore;
+ sBrkPtInfo.m_bPending = sBrkPtInfoRec.m_bPending;
+ sBrkPtInfo.m_bCondition = sBrkPtInfoRec.m_bCondition;
+ sBrkPtInfo.m_strCondition = sBrkPtInfoRec.m_strCondition;
+ sBrkPtInfo.m_bBrkPtThreadId = sBrkPtInfoRec.m_bBrkPtThreadId;
+ sBrkPtInfo.m_nBrkPtThreadId = sBrkPtInfoRec.m_nBrkPtThreadId;
+
+ // MI print "=breakpoint-modified,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%08x\", func=\"%s\",file=\"%s\",fullname=\"%s/%s\",line=\"%d\",times=\"%d\",original-location=\"%s\"}"
+ CMICmnMIValueTuple miValueTuple;
+ if( !rSessionInfo.MIResponseFormBrkPtInfo( sBrkPtInfo, miValueTuple ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_FORM_MI_RESPONSE ), "HandleEventSBBreakpointCmn()" ) );
+ return MIstatus::failure;
+ }
+
+ const CMICmnMIValueResult miValueResultC( "bkpt", miValueTuple );
+ const CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_BreakPointModified, miValueResultC );
+ const bool bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Handle a LLDB SBBreakpoint added event.
+// Add more breakpoint information or overwrite existing information.
+// Normally a break point session info objects exists by now when an MI command
+// was issued to insert a break so the retrieval would normally always succeed
+// however should a user type "b main" into a console then LLDB will create a
+// breakpoint directly, hence no MI command, hence no previous record of the
+// breakpoint so RecordBrkPtInfoGet() will fail. We still get the event though
+// so need to create a breakpoint info object here and send appropriate MI
+// response.
+// Type: Method.
+// Args: vEvent - (R) An LLDB broadcast event.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakpointAdded( const lldb::SBEvent & vEvent )
+{
+ lldb::SBBreakpoint brkPt = lldb::SBBreakpoint::GetBreakpointFromEvent( vEvent );
+ if( !brkPt.IsValid() )
+ return MIstatus::success;
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfo;
+ if( !rSessionInfo.GetBrkPtInfo( brkPt, sBrkPtInfo ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_BRKPT_INFO_GET ), "HandleEventSBBreakpointAdded()", brkPt.GetID() ) );
+ return MIstatus::failure;
+ }
+
+ // CODETAG_LLDB_BREAKPOINT_CREATION
+ // This is in a worker thread
+ CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfoRec;
+ const bool bBrkPtExistAlready = rSessionInfo.RecordBrkPtInfoGet( brkPt.GetID(), sBrkPtInfoRec );
+ if( bBrkPtExistAlready )
+ {
+ // Update breakpoint information object
+ sBrkPtInfo.m_bDisp = sBrkPtInfoRec.m_bDisp;
+ sBrkPtInfo.m_bEnabled = brkPt.IsEnabled();
+ sBrkPtInfo.m_bHaveArgOptionThreadGrp = false;
+ sBrkPtInfo.m_strOptThrdGrp.clear();
+ sBrkPtInfo.m_nTimes = brkPt.GetHitCount();
+ sBrkPtInfo.m_strOrigLoc = sBrkPtInfoRec.m_strOrigLoc;
+ sBrkPtInfo.m_nIgnore = sBrkPtInfoRec.m_nIgnore;
+ sBrkPtInfo.m_bPending = sBrkPtInfoRec.m_bPending;
+ sBrkPtInfo.m_bCondition = sBrkPtInfoRec.m_bCondition;
+ sBrkPtInfo.m_strCondition = sBrkPtInfoRec.m_strCondition;
+ sBrkPtInfo.m_bBrkPtThreadId = sBrkPtInfoRec.m_bBrkPtThreadId;
+ sBrkPtInfo.m_nBrkPtThreadId = sBrkPtInfoRec.m_nBrkPtThreadId;
+ }
+ else
+ {
+ // Create a breakpoint information object
+ sBrkPtInfo.m_bDisp = brkPt.IsOneShot();
+ sBrkPtInfo.m_bEnabled = brkPt.IsEnabled();
+ sBrkPtInfo.m_bHaveArgOptionThreadGrp = false;
+ sBrkPtInfo.m_strOptThrdGrp.clear();
+ sBrkPtInfo.m_strOrigLoc = CMIUtilString::Format( "%s:%d", sBrkPtInfo.m_fileName.c_str(), sBrkPtInfo.m_nLine );
+ sBrkPtInfo.m_nIgnore = brkPt.GetIgnoreCount();
+ sBrkPtInfo.m_bPending = false;
+ const MIchar * pStrCondition = brkPt.GetCondition();
+ sBrkPtInfo.m_bCondition = (pStrCondition != nullptr) ? true : false;
+ sBrkPtInfo.m_strCondition = (pStrCondition != nullptr) ? pStrCondition : "??";
+ sBrkPtInfo.m_bBrkPtThreadId = (brkPt.GetThreadID() != 0) ? true : false;
+ sBrkPtInfo.m_nBrkPtThreadId = brkPt.GetThreadID();
+ }
+
+ CMICmnMIValueTuple miValueTuple;
+ if( !rSessionInfo.MIResponseFormBrkPtInfo( sBrkPtInfo, miValueTuple ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_FORM_MI_RESPONSE ), "HandleEventSBBreakpointAdded()" ) );
+ return MIstatus::failure;
+ }
+
+ bool bOk = MIstatus::success;
+ if( bBrkPtExistAlready )
+ {
+ // MI print "=breakpoint-modified,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%08x\",func=\"%s\",file=\"%s\",fullname=\"%s/%s\",line=\"%d\",times=\"%d\",original-location=\"%s\"}"
+ const CMICmnMIValueResult miValueResult( "bkpt", miValueTuple );
+ const CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_BreakPointModified, miValueResult );
+ bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord );
+ }
+ else
+ {
+ // CODETAG_LLDB_BRKPT_ID_MAX
+ if( brkPt.GetID() > (lldb::break_id_t) rSessionInfo.m_nBrkPointCntMax )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_CNT_EXCEEDED ), "HandleEventSBBreakpointAdded()", rSessionInfo.m_nBrkPointCntMax, sBrkPtInfo.m_id ) );
+ return MIstatus::failure;
+ }
+ if( !rSessionInfo.RecordBrkPtInfo( brkPt.GetID(), sBrkPtInfo ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_BRKPT_INFO_SET ), "HandleEventSBBreakpointAdded()", sBrkPtInfo.m_id ) );
+ return MIstatus::failure;
+ }
+
+ // MI print "=breakpoint-created,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%08x\",func=\"%s\",file=\"%s\",fullname=\"%s/%s\",line=\"%d\",times=\"%d\",original-location=\"%s\"}"
+ const CMICmnMIValueResult miValueResult( "bkpt", miValueTuple );
+ const CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_BreakPointCreated, miValueResult );
+ bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Handle a LLDB SBThread event.
+// Type: Method.
+// Args: vEvent - (R) An LLDB broadcast event.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBThread( const lldb::SBEvent & vEvent )
+{
+ if( !ChkForStateChanges() )
+ return MIstatus::failure;
+
+ bool bOk = MIstatus::success;
+ const MIchar * pEventType = "";
+ const MIuint nEventType = vEvent.GetType();
+ switch( nEventType )
+ {
+ case lldb::SBThread::eBroadcastBitStackChanged:
+ pEventType = "eBroadcastBitStackChanged";
+ bOk = HandleEventSBThreadBitStackChanged( vEvent );
+ break;
+ case lldb::SBThread::eBroadcastBitThreadSuspended:
+ pEventType = "eBroadcastBitThreadSuspended";
+ bOk = HandleEventSBThreadSuspended( vEvent );
+ break;
+ case lldb::SBThread::eBroadcastBitThreadResumed:
+ pEventType = "eBroadcastBitThreadResumed";
+ break;
+ case lldb::SBThread::eBroadcastBitSelectedFrameChanged:
+ pEventType = "eBroadcastBitSelectedFrameChanged";
+ break;
+ case lldb::SBThread::eBroadcastBitThreadSelected:
+ pEventType = "eBroadcastBitThreadSelected";
+ break;
+ default:
+ {
+ const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT ), "SBThread", (MIuint) nEventType ) );
+ SetErrorDescription( msg );
+ return MIstatus::failure;
+ }
+ }
+ m_pLog->WriteLog( CMIUtilString::Format( "##### An SBThread event occurred: %s", pEventType ) );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Handle a LLDB SBThread event.
+// Type: Method.
+// Args: vEvent - (R) An LLDB broadcast event.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBThreadSuspended( const lldb::SBEvent & vEvent )
+{
+ lldb::SBThread thread = lldb::SBThread::GetThreadFromEvent( vEvent );
+ if( !thread.IsValid() )
+ return MIstatus::success;
+
+ const lldb::StopReason eStopReason = thread.GetStopReason();
+ if( eStopReason != lldb::eStopReasonSignal )
+ return MIstatus::success;
+
+ // MI print "@thread=%d,signal=%lld"
+ const MIuint64 nId = thread.GetStopReasonDataAtIndex( 0 );
+ const CMIUtilString strThread( CMIUtilString::Format( "%d", thread.GetThreadID() ) );
+ const CMICmnMIValueConst miValueConst( strThread );
+ const CMICmnMIValueResult miValueResult( "thread", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Thread, miValueResult );
+ const CMIUtilString strSignal( CMIUtilString::Format( "%lld", nId ) );
+ const CMICmnMIValueConst miValueConst2( strSignal );
+ const CMICmnMIValueResult miValueResult2( "signal", miValueConst2 );
+ bool bOk = miOutOfBandRecord.Add( miValueResult2 );
+ bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Handle a LLDB SBThread event.
+// Type: Method.
+// Args: vEvent - (R) An LLDB broadcast event.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBThreadBitStackChanged( const lldb::SBEvent & vEvent )
+{
+ lldb::SBThread thread = lldb::SBThread::GetThreadFromEvent( vEvent );
+ if( !thread.IsValid() )
+ return MIstatus::success;
+
+ lldb::SBStream streamOut;
+ const bool bOk = thread.GetStatus( streamOut );
+ return bOk && TextToStdout( streamOut.GetData() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Handle a LLDB SBCommandInterpreter event.
+// Type: Method.
+// Args: vEvent - (R) An LLDB command interpreter event.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBCommandInterpreter( const lldb::SBEvent & vEvent )
+{
+ // This function is not used
+ // *** This function is under development
+
+ const MIchar * pEventType = "";
+ const MIuint nEventType = vEvent.GetType();
+ switch( nEventType )
+ {
+ case lldb::SBCommandInterpreter::eBroadcastBitThreadShouldExit:
+ pEventType ="eBroadcastBitThreadShouldExit";
+ // ToDo: IOR: Reminder to maybe handle this here
+ //const MIuint nEventType = event.GetType();
+ //if( nEventType & lldb::SBCommandInterpreter::eBroadcastBitThreadShouldExit )
+ //{
+ // m_pClientDriver->SetExitApplicationFlag();
+ // vrbYesExit = true;
+ // return MIstatus::success;
+ //} break;
+ case lldb::SBCommandInterpreter::eBroadcastBitResetPrompt:
+ pEventType = "eBroadcastBitResetPrompt";
+ break;
+ case lldb::SBCommandInterpreter::eBroadcastBitQuitCommandReceived:
+ pEventType = "eBroadcastBitQuitCommandReceived";
+ break;
+ case lldb::SBCommandInterpreter::eBroadcastBitAsynchronousOutputData:
+ pEventType = "eBroadcastBitAsynchronousOutputData";
+ break;
+ case lldb::SBCommandInterpreter::eBroadcastBitAsynchronousErrorData:
+ pEventType = "eBroadcastBitAsynchronousErrorData";
+ break;
+ default:
+ {
+ const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT ), "SBCommandInterpreter", (MIuint) nEventType ) );
+ SetErrorDescription( msg );
+ return MIstatus::failure;
+ }
+ }
+ m_pLog->WriteLog( CMIUtilString::Format( "##### An SBCommandInterpreter event occurred: %s", pEventType ) );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Handle SBProcess event eBroadcastBitStateChanged.
+// Type: Method.
+// Args: vEvent - (R) An LLDB event object.
+// vrbExitAppEvent - (W) True - Received LLDB exit app event, false = did not.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventBroadcastBitStateChanged( const lldb::SBEvent & vEvent, bool & vrbExitAppEvent )
+{
+ bool bOk = ChkForStateChanges();
+ bOk = bOk && GetProcessStdout();
+ bOk = bOk && GetProcessStderr();
+ if( !bOk )
+ return MIstatus::failure;
+
+ // Something changed in the process; get the event and report the process's current
+ // status and location
+ const lldb::StateType eEventState = lldb::SBProcess::GetStateFromEvent( vEvent );
+ if( eEventState == lldb::eStateInvalid )
+ return MIstatus::success;
+
+ lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent( vEvent );
+ if( !process.IsValid() )
+ {
+ const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_PROCESS_INVALID ), "SBProcess", "HandleProcessEventBroadcastBitStateChanged()" ) );
+ SetErrorDescription( msg );
+ return MIstatus::failure;
+ }
+
+ bool bShouldBrk = true;
+ const MIchar * pEventType = "";
+ switch( eEventState )
+ {
+ case lldb::eStateUnloaded:
+ pEventType = "eStateUnloaded";
+ break;
+ case lldb::eStateConnected:
+ pEventType = "eStateConnected";
+ break;
+ case lldb::eStateAttaching:
+ pEventType = "eStateAttaching";
+ break;
+ case lldb::eStateLaunching:
+ pEventType ="eStateLaunching";
+ break;
+ case lldb::eStateStopped:
+ pEventType = "eStateStopped";
+ bOk = HandleProcessEventStateStopped( bShouldBrk );
+ if( bShouldBrk )
+ break;
+ case lldb::eStateCrashed:
+ case lldb::eStateSuspended:
+ pEventType = "eStateSuspended";
+ bOk = HandleProcessEventStateSuspended( vEvent );
+ break;
+ case lldb::eStateRunning:
+ pEventType = "eStateRunning";
+ bOk = HandleProcessEventStateRunning();
+ break;
+ case lldb::eStateStepping:
+ pEventType = "eStateStepping";
+ break;
+ case lldb::eStateDetached:
+ pEventType = "eStateDetached";
+ break;
+ case lldb::eStateExited:
+ pEventType = "eStateExited";
+ vrbExitAppEvent = true;
+ bOk = HandleProcessEventStateExited();
+ break;
+ default:
+ {
+ const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT ), "SBProcess BroadcastBitStateChanged", (MIuint) eEventState ) );
+ SetErrorDescription( msg );
+ return MIstatus::failure;
+ }
+ }
+
+ // ToDo: Remove when finished coding application
+ m_pLog->WriteLog( CMIUtilString::Format( "##### An SB Process event BroadcastBitStateChanged occurred: %s", pEventType ) );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Asynchronous event handler for LLDB Process state suspended.
+// Type: Method.
+// Args: vEvent - (R) An LLDB event object.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateSuspended( const lldb::SBEvent & vEvent )
+{
+ // Make sure the program hasn't been auto-restarted:
+ if( lldb::SBProcess::GetRestartedFromEvent( vEvent ) )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+ lldb::SBDebugger & rDebugger = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger;
+ lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess;
+ lldb::SBTarget target = rProcess.GetTarget();
+ if( rDebugger.GetSelectedTarget() == target )
+ {
+ if( !UpdateSelectedThread() )
+ return MIstatus::failure;
+
+ lldb::SBCommandReturnObject result;
+ const lldb::ReturnStatus status = rDebugger.GetCommandInterpreter().HandleCommand( "process status", result, false ); MIunused( status );
+ bOk = TextToStderr( result.GetError() );
+ bOk = bOk && TextToStdout( result.GetOutput() );
+ }
+ else
+ {
+ lldb::SBStream streamOut;
+ const MIuint nTargetIndex = rDebugger.GetIndexOfTarget( target );
+ if( nTargetIndex != UINT_MAX )
+ streamOut.Printf( "Target %d: (", nTargetIndex );
+ else
+ streamOut.Printf( "Target <unknown index>: (" );
+ target.GetDescription( streamOut, lldb::eDescriptionLevelBrief );
+ streamOut.Printf( ") stopped.\n" );
+ bOk = TextToStdout( streamOut.GetData() );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Print to stdout MI formatted text to indicate process stopped.
+// Type: Method.
+// Args: vwrbShouldBrk - (W) True = Yes break, false = do not.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateStopped( bool & vwrbShouldBrk )
+{
+ if( !UpdateSelectedThread() )
+ return MIstatus::failure;
+
+ const MIchar * pEventType = "";
+ bool bOk = MIstatus::success;
+ lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess;
+ const lldb::StopReason eStoppedReason = rProcess.GetSelectedThread().GetStopReason();
+ switch( eStoppedReason )
+ {
+ case lldb::eStopReasonInvalid:
+ pEventType = "eStopReasonInvalid";
+ vwrbShouldBrk = false;
+ break;
+ case lldb::eStopReasonNone:
+ pEventType = "eStopReasonNone";
+ break;
+ case lldb::eStopReasonTrace:
+ pEventType = "eStopReasonTrace";
+ bOk = HandleProcessEventStopReasonTrace();
+ break;
+ case lldb::eStopReasonBreakpoint:
+ pEventType = "eStopReasonBreakpoint";
+ bOk = HandleProcessEventStopReasonBreakpoint();
+ break;
+ case lldb::eStopReasonWatchpoint:
+ pEventType = "eStopReasonWatchpoint";
+ break;
+ case lldb::eStopReasonSignal:
+ pEventType = "eStopReasonSignal";
+ bOk = HandleProcessEventStopSignal( vwrbShouldBrk );
+ break;
+ case lldb::eStopReasonException:
+ pEventType ="eStopReasonException";
+ break;
+ case lldb::eStopReasonExec:
+ pEventType = "eStopReasonExec";
+ break;
+ case lldb::eStopReasonPlanComplete:
+ pEventType = "eStopReasonPlanComplete";
+ bOk = HandleProcessEventStopReasonTrace();
+ break;
+ case lldb::eStopReasonThreadExiting:
+ pEventType = "eStopReasonThreadExiting";
+ break;
+ default:
+ {
+ vwrbShouldBrk = false;
+
+ // MI print "*stopped,reason=\"%d\",stopped-threads=\"all\",from-thread=\"%u\""
+ const CMIUtilString strReason( CMIUtilString::Format( "%d", eStoppedReason ) );
+ const CMICmnMIValueConst miValueConst( strReason );
+ const CMICmnMIValueResult miValueResult( "reason", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult );
+ const CMICmnMIValueConst miValueConst2( "all" );
+ const CMICmnMIValueResult miValueResult2( "stopped-threads", miValueConst2 );
+ bOk = miOutOfBandRecord.Add( miValueResult2 );
+ const CMIUtilString strFromThread( CMIUtilString::Format( "%u", rProcess.GetSelectedThread().GetIndexID() ) );
+ const CMICmnMIValueConst miValueConst3( strFromThread );
+ const CMICmnMIValueResult miValueResult3( "from-thread", miValueConst3 );
+ bOk = bOk && miOutOfBandRecord.Add( miValueResult3 );
+ bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord );
+ bOk = bOk && TextToStdout( "(gdb)" );
+ }
+ }
+
+ // ToDo: Remove when finished coding application
+ m_pLog->WriteLog( CMIUtilString::Format( "##### An SB Process event stop state occurred: %s", pEventType ) );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Asynchronous event handler for LLDB Process stop signal.
+// Type: Method.
+// Args: vwrbShouldBrk - (W) True = Yes break, false = do not.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopSignal( bool & vwrbShouldBrk )
+{
+ bool bOk = MIstatus::success;
+
+ lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess;
+ const MIuint64 nStopReason = rProcess.GetSelectedThread().GetStopReasonDataAtIndex( 0 );
+ switch( nStopReason )
+ {
+ case 2: // Terminal interrupt signal. SIGINT
+ {
+ // MI print "*stopped,reason=\"signal-received\",signal-name=\"SIGNINT\",signal-meaning=\"Interrupt\",frame={%s}"
+ const CMICmnMIValueConst miValueConst( "signal-received" );
+ const CMICmnMIValueResult miValueResult( "reason", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult );
+ const CMICmnMIValueConst miValueConst2( "SIGINT" );
+ const CMICmnMIValueResult miValueResult2( "signal-name", miValueConst2 );
+ bOk = miOutOfBandRecord.Add( miValueResult2 );
+ const CMICmnMIValueConst miValueConst3( "Interrupt" );
+ const CMICmnMIValueResult miValueResult3( "signal-meaning", miValueConst3 );
+ bOk = bOk && miOutOfBandRecord.Add( miValueResult3 );
+ CMICmnMIValueTuple miValueTuple;
+ bOk = bOk && MiHelpGetCurrentThreadFrame( miValueTuple );
+ const CMICmnMIValueResult miValueResult5( "frame", miValueTuple );
+ bOk = bOk && miOutOfBandRecord.Add( miValueResult5 );
+ bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord );
+ bOk = bOk && TextToStdout( "(gdb)" );
+ }
+ break;
+ case 11: // Invalid memory reference. SIGSEGV
+ {
+ // MI print "*stopped,reason=\"signal-received\",signal-name=\"SIGSEGV\",signal-meaning=\"Segmentation fault\",thread-id=\"%d\",frame={%s}"
+ const CMICmnMIValueConst miValueConst( "signal-received" );
+ const CMICmnMIValueResult miValueResult( "reason", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult );
+ const CMICmnMIValueConst miValueConst2( "SIGSEGV" );
+ const CMICmnMIValueResult miValueResult2( "signal-name", miValueConst2 );
+ bOk = miOutOfBandRecord.Add( miValueResult2 );
+ const CMICmnMIValueConst miValueConst3( "Segmentation fault" );
+ const CMICmnMIValueResult miValueResult3( "signal-meaning", miValueConst3 );
+ bOk = bOk && miOutOfBandRecord.Add( miValueResult3 );
+ const CMIUtilString strThreadId( CMIUtilString::Format( "%d", rProcess.GetSelectedThread().GetIndexID() ) );
+ const CMICmnMIValueConst miValueConst4( strThreadId );
+ const CMICmnMIValueResult miValueResult4( "thread-id", miValueConst4 );
+ bOk = bOk && miOutOfBandRecord.Add( miValueResult4 );
+ CMICmnMIValueTuple miValueTuple;
+ bOk = bOk && MiHelpGetCurrentThreadFrame( miValueTuple );
+ const CMICmnMIValueResult miValueResult5( "frame", miValueTuple );
+ bOk = bOk && miOutOfBandRecord.Add( miValueResult5 );
+ bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord );
+ // Note no "(gdb)" output here
+ }
+ break;
+ case 19:
+ if( rProcess.IsValid() )
+ rProcess.Continue();
+ break;
+ case 5: // Trace/breakpoint trap. SIGTRAP
+ {
+ lldb::SBThread thread = rProcess.GetSelectedThread();
+ const MIuint nFrames = thread.GetNumFrames();
+ if( nFrames > 0 )
+ {
+ lldb::SBFrame frame = thread.GetFrameAtIndex( 0 );
+ const char * pFnName = frame.GetFunctionName();
+ if( pFnName != nullptr )
+ {
+ const CMIUtilString fnName = CMIUtilString( pFnName );
+ static const CMIUtilString threadCloneFn = CMIUtilString( "__pthread_clone" );
+
+ if( CMIUtilString::Compare( threadCloneFn, fnName ) )
+ {
+ if( rProcess.IsValid() )
+ {
+ rProcess.Continue();
+ vwrbShouldBrk = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ default:
+ {
+ // MI print "*stopped,reason=\"signal-received\",signal=\"%lld\",stopped-threads=\"all\""
+ const CMICmnMIValueConst miValueConst( "signal-received" );
+ const CMICmnMIValueResult miValueResult( "reason", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult );
+ const CMIUtilString strReason( CMIUtilString::Format( "%lld", nStopReason ) );
+ const CMICmnMIValueConst miValueConst2( strReason );
+ const CMICmnMIValueResult miValueResult2( "signal", miValueConst2 );
+ bOk = miOutOfBandRecord.Add( miValueResult2 );
+ const CMICmnMIValueConst miValueConst3( "all" );
+ const CMICmnMIValueResult miValueResult3( "stopped-threads", miValueConst3 );
+ bOk = bOk && miOutOfBandRecord.Add( miValueResult3 );
+ bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord );
+ bOk = bOk && TextToStdout( "(gdb)" );
+ }
+ } // switch( nStopReason )
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Form partial MI response in a MI value tuple object.
+// Type: Method.
+// Args: vwrMiValueTuple - (W) MI value tuple object.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::MiHelpGetCurrentThreadFrame( CMICmnMIValueTuple & vwrMiValueTuple )
+{
+ CMIUtilString strThreadFrame;
+ lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess;
+ lldb::SBThread thread = rProcess.GetSelectedThread();
+ const MIuint nFrame = thread.GetNumFrames();
+ if( nFrame == 0 )
+ {
+ // MI print "addr=\"??\",func=\"??\",file=\"??\",fullname=\"??\",line=\"??\""
+ const CMICmnMIValueConst miValueConst( "??" );
+ const CMICmnMIValueResult miValueResult( "addr", miValueConst );
+ CMICmnMIValueTuple miValueTuple( miValueResult );
+ const CMICmnMIValueResult miValueResult2( "func", miValueConst );
+ miValueTuple.Add( miValueResult2 );
+ const CMICmnMIValueResult miValueResult4( "file", miValueConst );
+ miValueTuple.Add( miValueResult4 );
+ const CMICmnMIValueResult miValueResult5( "fullname", miValueConst );
+ miValueTuple.Add( miValueResult5 );
+ const CMICmnMIValueResult miValueResult6( "line", miValueConst );
+ miValueTuple.Add( miValueResult6 );
+
+ vwrMiValueTuple = miValueTuple;
+
+ return MIstatus::success;
+ }
+
+ CMICmnMIValueTuple miValueTuple;
+ if( !CMICmnLLDBDebugSessionInfo::Instance().MIResponseFormFrameInfo( thread, 0, miValueTuple ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_FORM_MI_RESPONSE ), "MiHelpGetCurrentThreadFrame()" ) );
+ return MIstatus::failure;
+ }
+
+ vwrMiValueTuple = miValueTuple;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Asynchronous event handler for LLDB Process stop reason breakpoint.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopReasonBreakpoint( void )
+{
+ // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
+ if( !CMIDriver::Instance().SetDriverStateRunningNotDebugging() )
+ {
+ const CMIUtilString & rErrMsg( CMIDriver::Instance().GetErrorDescription() );
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_SETNEWDRIVERSTATE ), "HandleProcessEventStopReasonBreakpoint()", rErrMsg.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess;
+ const MIuint64 brkPtId = rProcess.GetSelectedThread().GetStopReasonDataAtIndex( 0 );
+ lldb::SBBreakpoint brkPt = CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget.GetBreakpointAtIndex( (MIuint) brkPtId );
+
+ return MiStoppedAtBreakPoint( brkPtId, brkPt );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Form the MI Out-of-band response for stopped reason on hitting a break point.
+// Type: Method.
+// Args: vBrkPtId - (R) The LLDB break point's ID
+// vBrkPt - (R) THe LLDB break point object.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::MiStoppedAtBreakPoint( const MIuint64 vBrkPtId, const lldb::SBBreakpoint & vBrkPt )
+{
+ bool bOk = MIstatus::success;
+
+ lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess;
+ lldb::SBThread thread = rProcess.GetSelectedThread();
+ const MIuint nFrame = thread.GetNumFrames();
+ if( nFrame == 0 )
+ {
+ // MI print "*stopped,reason=\"breakpoint-hit\",disp=\"del\",bkptno=\"%d\",frame={},thread-id=\"%d\",stopped-threads=\"all\""
+ const CMICmnMIValueConst miValueConst( "breakpoint-hit" );
+ const CMICmnMIValueResult miValueResult( "reason", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult );
+ const CMICmnMIValueConst miValueConst2( "del" );
+ const CMICmnMIValueResult miValueResult2( "disp", miValueConst2 );
+ bOk = miOutOfBandRecord.Add( miValueResult2 );
+ const CMIUtilString strBkp( CMIUtilString::Format( "%d", vBrkPtId ) );
+ const CMICmnMIValueConst miValueConst3( strBkp );
+ CMICmnMIValueResult miValueResult3( "bkptno", miValueConst3 );
+ bOk = bOk && miOutOfBandRecord.Add( miValueResult3 );
+ const CMICmnMIValueConst miValueConst4( "{}" );
+ const CMICmnMIValueResult miValueResult4( "frame", miValueConst4 );
+ bOk = bOk && miOutOfBandRecord.Add( miValueResult4 );
+ const CMIUtilString strThreadId( CMIUtilString::Format( "%d", vBrkPt.GetThreadIndex() ) );
+ const CMICmnMIValueConst miValueConst5( strThreadId );
+ const CMICmnMIValueResult miValueResult5( "thread-id", miValueConst5 );
+ bOk = bOk && miOutOfBandRecord.Add( miValueResult5 );
+ const CMICmnMIValueConst miValueConst6( "all" );
+ const CMICmnMIValueResult miValueResult6( "stopped-threads", miValueConst6 );
+ bOk = bOk && miOutOfBandRecord.Add( miValueResult6 );
+ bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord );
+ bOk = bOk && TextToStdout( "(gdb)" );
+ return bOk;
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSession = CMICmnLLDBDebugSessionInfo::Instance();
+
+ lldb::SBFrame frame = thread.GetFrameAtIndex( 0 );
+ lldb::addr_t pc = 0;
+ CMIUtilString fnName;
+ CMIUtilString fileName;
+ CMIUtilString path;
+ MIuint nLine = 0;
+ if( !rSession.GetFrameInfo( frame, pc, fnName, fileName, path, nLine ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_FRAME_INFO_GET ), "MiStoppedAtBreakPoint()" ) );
+ return MIstatus::failure;
+ }
+
+ // MI print "*stopped,reason=\"breakpoint-hit\",disp=\"del\",bkptno=\"%d\",frame={addr=\"0x%08x\",func=\"%s\",args=[],file=\"%s\",fullname=\"%s\",line=\"%d\"},thread-id=\"%d\",stopped-threads=\"all\""
+ const CMICmnMIValueConst miValueConst( "breakpoint-hit" );
+ const CMICmnMIValueResult miValueResult( "reason", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult );
+ const CMICmnMIValueConst miValueConstA( "del" );
+ const CMICmnMIValueResult miValueResultA( "disp", miValueConstA );
+ bOk = miOutOfBandRecord.Add( miValueResultA );
+ const CMIUtilString strBkp( CMIUtilString::Format( "%d", vBrkPtId ) );
+ const CMICmnMIValueConst miValueConstB( strBkp );
+ CMICmnMIValueResult miValueResultB( "bkptno", miValueConstB );
+ bOk = bOk && miOutOfBandRecord.Add( miValueResultB );
+
+ // frame={addr=\"0x%08x\",func=\"%s\",args=[],file=\"%s\",fullname=\"%s\",line=\"%d\"}
+ if( bOk )
+ {
+ CMICmnMIValueList miValueList( true );
+ const MIuint maskVarTypes = 0x1000;
+ bOk = rSession.MIResponseFormVariableInfo2( frame, maskVarTypes, miValueList );
+
+ CMICmnMIValueTuple miValueTuple;
+ bOk = bOk && rSession.MIResponseFormFrameInfo2( pc, miValueList.GetString(), fnName, fileName, path, nLine, miValueTuple );
+ const CMICmnMIValueResult miValueResult8( "frame", miValueTuple );
+ bOk = bOk && miOutOfBandRecord.Add( miValueResult8 );
+ }
+
+ // Add to MI thread-id=\"%d\",stopped-threads=\"all\"
+ if( bOk )
+ {
+ const CMIUtilString strThreadId( CMIUtilString::Format( "%d", thread.GetIndexID() ) );
+ const CMICmnMIValueConst miValueConst8( strThreadId );
+ const CMICmnMIValueResult miValueResult8( "thread-id", miValueConst8 );
+ bOk = miOutOfBandRecord.Add( miValueResult8 );
+ }
+ if( bOk )
+ {
+ const CMICmnMIValueConst miValueConst9( "all" );
+ const CMICmnMIValueResult miValueResult9( "stopped-threads", miValueConst9 );
+ bOk = miOutOfBandRecord.Add( miValueResult9 );
+ bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord );
+ bOk = bOk && TextToStdout( "(gdb)" );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Asynchronous event handler for LLDB Process stop reason trace.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopReasonTrace( void )
+{
+ bool bOk = true;
+ lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess;
+ lldb::SBThread thread = rProcess.GetSelectedThread();
+ const MIuint nFrame = thread.GetNumFrames();
+ if( nFrame == 0 )
+ {
+ // MI print "*stopped,reason=\"trace\",stopped-threads=\"all\""
+ const CMICmnMIValueConst miValueConst( "trace" );
+ const CMICmnMIValueResult miValueResult( "reason", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult );
+ const CMICmnMIValueConst miValueConst2( "all" );
+ const CMICmnMIValueResult miValueResult2( "stopped-threads", miValueConst2 );
+ bOk = miOutOfBandRecord.Add( miValueResult2 );
+ bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord );
+ bOk = bOk && TextToStdout( "(gdb)" );
+ return bOk;
+ }
+
+ CMICmnLLDBDebugSessionInfo & rSession = CMICmnLLDBDebugSessionInfo::Instance();
+
+ // MI print "*stopped,reason=\"end-stepping-range\",frame={addr=\"0x%08x\",func=\"%s\",args=[\"%s\"],file=\"%s\",fullname=\"%s\",line=\"%d\"},thread-id=\"%d\",stopped-threads=\"all\""
+ lldb::SBFrame frame = thread.GetFrameAtIndex( 0 );
+ lldb::addr_t pc = 0;
+ CMIUtilString fnName;
+ CMIUtilString fileName;
+ CMIUtilString path;
+ MIuint nLine = 0;
+ if( !rSession.GetFrameInfo( frame, pc, fnName, fileName, path, nLine ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_FRAME_INFO_GET ), "HandleProcessEventStopReasonTrace()" ) );
+ return MIstatus::failure;
+ }
+
+ // Function args
+ CMICmnMIValueList miValueList( true );
+ const MIuint maskVarTypes = 0x1000;
+ if( !rSession.MIResponseFormVariableInfo2( frame, maskVarTypes, miValueList ) )
+ return MIstatus::failure;
+ CMICmnMIValueTuple miValueTuple;
+ if( !rSession.MIResponseFormFrameInfo2( pc, miValueList.GetString(), fnName, fileName, path, nLine, miValueTuple ) )
+ return MIstatus::failure;
+
+ const CMICmnMIValueConst miValueConst( "end-stepping-range" );
+ const CMICmnMIValueResult miValueResult( "reason", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult );
+ const CMICmnMIValueResult miValueResult2( "frame", miValueTuple );
+ bOk = miOutOfBandRecord.Add( miValueResult2 );
+
+ // Add to MI thread-id=\"%d\",stopped-threads=\"all\"
+ if( bOk )
+ {
+ const CMIUtilString strThreadId( CMIUtilString::Format( "%d", thread.GetIndexID() ) );
+ const CMICmnMIValueConst miValueConst8( strThreadId );
+ const CMICmnMIValueResult miValueResult8( "thread-id", miValueConst8 );
+ bOk = miOutOfBandRecord.Add( miValueResult8 );
+ }
+ if( bOk )
+ {
+ const CMICmnMIValueConst miValueConst9( "all" );
+ const CMICmnMIValueResult miValueResult9( "stopped-threads", miValueConst9 );
+ bOk = miOutOfBandRecord.Add( miValueResult9 );
+ bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord );
+ bOk = bOk && TextToStdout( "(gdb)" );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Asynchronous function update selected thread.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::UpdateSelectedThread( void )
+{
+ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess();
+ if( !process.IsValid() )
+ return MIstatus::success;
+
+ lldb::SBThread currentThread = process.GetSelectedThread();
+ lldb::SBThread thread;
+ const lldb::StopReason eCurrentThreadStoppedReason = currentThread.GetStopReason();
+ if( !currentThread.IsValid() || (eCurrentThreadStoppedReason == lldb::eStopReasonInvalid) || (eCurrentThreadStoppedReason == lldb::eStopReasonNone) )
+ {
+ // Prefer a thread that has just completed its plan over another thread as current thread
+ lldb::SBThread planThread;
+ lldb::SBThread otherThread;
+ const size_t nThread = process.GetNumThreads();
+ for( MIuint i = 0; i < nThread; i++ )
+ {
+ // GetThreadAtIndex() uses a base 0 index
+ // GetThreadByIndexID() uses a base 1 index
+ thread = process.GetThreadAtIndex( i );
+ const lldb::StopReason eThreadStopReason = thread.GetStopReason();
+ switch( eThreadStopReason )
+ {
+ case lldb::eStopReasonTrace:
+ case lldb::eStopReasonBreakpoint:
+ case lldb::eStopReasonWatchpoint:
+ case lldb::eStopReasonSignal:
+ case lldb::eStopReasonException:
+ if( !otherThread.IsValid() )
+ otherThread = thread;
+ break;
+ case lldb::eStopReasonPlanComplete:
+ if( !planThread.IsValid() )
+ planThread = thread;
+ break;
+ case lldb::eStopReasonInvalid:
+ case lldb::eStopReasonNone:
+ default:
+ break;
+ }
+ }
+ if( planThread.IsValid() )
+ process.SetSelectedThread( planThread );
+ else if( otherThread.IsValid() )
+ process.SetSelectedThread( otherThread );
+ else
+ {
+ if( currentThread.IsValid() )
+ thread = currentThread;
+ else
+ thread = process.GetThreadAtIndex( 0 );
+
+ if( thread.IsValid() )
+ process.SetSelectedThread( thread );
+ }
+ } // if( !currentThread.IsValid() || (eCurrentThreadStoppedReason == lldb::eStopReasonInvalid) || (eCurrentThreadStoppedReason == lldb::eStopReasonNone) )
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Print to stdout "*running,thread-id=\"all\"", "(gdb)".
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateRunning( void )
+{
+ CMICmnMIValueConst miValueConst( "all" );
+ CMICmnMIValueResult miValueResult( "thread-id", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Running, miValueResult );
+ bool bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord );
+ bOk = bOk && TextToStdout( "(gdb)" );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Print to stdout "=thread-exited,id=\"%ld\",group-id=\"i1\"",
+// "=thread-group-exited,id=\"i1\",exit-code=\"0\""),
+// "*stopped,reason=\"exited-normally\"",
+// "(gdb)"
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateExited( void )
+{
+ const CMIUtilString strId( CMIUtilString::Format( "%ld", 1 ) );
+ CMICmnMIValueConst miValueConst( strId );
+ CMICmnMIValueResult miValueResult( "id", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadExited, miValueResult );
+ CMICmnMIValueConst miValueConst2( "i1" );
+ CMICmnMIValueResult miValueResult2( "group-id", miValueConst2 );
+ bool bOk = miOutOfBandRecord.Add( miValueResult2 );
+ bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord );
+ if( bOk )
+ {
+ CMICmnMIValueConst miValueConst3( "i1" );
+ CMICmnMIValueResult miValueResult3( "id", miValueConst3 );
+ CMICmnMIOutOfBandRecord miOutOfBandRecord2( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupExited, miValueResult3 );
+ CMICmnMIValueConst miValueConst2( "0" );
+ CMICmnMIValueResult miValueResult2( "exit-code", miValueConst2 );
+ bOk = miOutOfBandRecord2.Add( miValueResult2 );
+ bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord2 );
+ }
+ if( bOk )
+ {
+ CMICmnMIValueConst miValueConst4( "exited-normally" );
+ CMICmnMIValueResult miValueResult4( "reason", miValueConst4 );
+ CMICmnMIOutOfBandRecord miOutOfBandRecord3( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult4 );
+ bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord3 );
+ }
+ bOk = bOk && TextToStdout( "(gdb)" );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Drain all stdout so we don't see any output come after we print our prompts.
+// The process has stuff waiting for stdout; get it and write it out to the
+// appropriate place.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::GetProcessStdout( void )
+{
+ bool bOk = MIstatus::success;
+
+ char c;
+ size_t nBytes = 0;
+ CMIUtilString text;
+ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess();
+ while( process.GetSTDOUT( &c, 1 ) > 0 )
+ {
+ CMIUtilString str;
+ if( ConvertPrintfCtrlCodeToString( c, str ) )
+ text += str;
+ nBytes++;
+ }
+ if( nBytes > 0 )
+ {
+ const CMIUtilString t( CMIUtilString::Format( "~\"%s\"", text.c_str() ) );
+ bOk = TextToStdout( t );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Drain all stderr so we don't see any output come after we print our prompts.
+// The process has stuff waiting for stderr; get it and write it out to the
+// appropriate place.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::GetProcessStderr( void )
+{
+ bool bOk = MIstatus::success;
+
+ char c;
+ size_t nBytes = 0;
+ CMIUtilString text;
+ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess();
+ while( process.GetSTDERR( &c, 1 ) > 0 )
+ {
+ CMIUtilString str;
+ if( ConvertPrintfCtrlCodeToString( c, str ) )
+ text += str;
+ nBytes++;
+ }
+ if( nBytes > 0 )
+ {
+ const CMIUtilString t( CMIUtilString::Format( "~\"%s\"", text.c_str() ) );
+ bOk = TextToStdout( t );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Convert text stream control codes to text equivalent.
+// Type: Method.
+// Args: vCtrl - (R) The control code.
+// vwrStrEquivalent - (W) The text equivalent.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::ConvertPrintfCtrlCodeToString( const MIchar vCtrl, CMIUtilString & vwrStrEquivalent )
+{
+ switch( vCtrl )
+ {
+ case '\033': vwrStrEquivalent = "\\e"; break;
+ case '\a': vwrStrEquivalent = "\\a"; break;
+ case '\b': vwrStrEquivalent = "\\b"; break;
+ case '\f': vwrStrEquivalent = "\\f"; break;
+ case '\n': vwrStrEquivalent = "\\n"; break;
+ case '\r': vwrStrEquivalent = "\\r"; break;
+ case '\t': vwrStrEquivalent = "\\t"; break;
+ case '\v': vwrStrEquivalent = "\\v"; break;
+ default:
+ vwrStrEquivalent = CMIUtilString::Format( "%c", vCtrl );
+ break;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Asynchronous event function check for state changes.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::ChkForStateChanges( void )
+{
+ lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess;
+ if( !rProcess.IsValid() )
+ return MIstatus::success;
+ lldb::SBTarget & rTarget = CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget;
+ if( !rTarget.IsValid() )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+
+ // Check for created threads
+ const MIuint nThread = rProcess.GetNumThreads();
+ for( MIuint i = 0; i < nThread; i++ )
+ {
+ // GetThreadAtIndex() uses a base 0 index
+ // GetThreadByIndexID() uses a base 1 index
+ lldb::SBThread thread = rProcess.GetThreadAtIndex( i );
+ if( !thread.IsValid() )
+ continue;
+
+ CMICmnLLDBDebugSessionInfo::VecActiveThreadId_t::const_iterator it = CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.begin();
+ bool bFound = false;
+ while( it != CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.end() )
+ {
+ const MIuint nThreadId = *it;
+ if( nThreadId == i )
+ {
+ bFound = true;
+ break;
+ }
+
+ // Next
+ ++it;
+ }
+ if( !bFound )
+ {
+ CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.push_back( i );
+
+ // Form MI "=thread-created,id=\"%d\",group-id=\"i1\""
+ const CMIUtilString strValue( CMIUtilString::Format( "%d", thread.GetIndexID() ) );
+ const CMICmnMIValueConst miValueConst( strValue );
+ const CMICmnMIValueResult miValueResult( "id", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBand( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadCreated, miValueResult );
+ const CMICmnMIValueConst miValueConst2( "i1" );
+ const CMICmnMIValueResult miValueResult2( "group-id", miValueConst2 );
+ bOk = miOutOfBand.Add( miValueResult2 );
+ bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBand );
+ if( !bOk )
+ return MIstatus::failure;
+ }
+ }
+
+ lldb::SBThread currentThread = rProcess.GetSelectedThread();
+ if( currentThread.IsValid() )
+ {
+ const MIuint threadId = currentThread.GetIndexID();
+ if( CMICmnLLDBDebugSessionInfo::Instance().m_currentSelectedThread != threadId )
+ {
+ CMICmnLLDBDebugSessionInfo::Instance().m_currentSelectedThread = threadId;
+
+ // Form MI "=thread-selected,id=\"%d\""
+ const CMIUtilString strValue( CMIUtilString::Format( "%d", currentThread.GetIndexID() ) );
+ const CMICmnMIValueConst miValueConst( strValue );
+ const CMICmnMIValueResult miValueResult( "id", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBand( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, miValueResult );
+ if( !MiOutOfBandRecordToStdout( miOutOfBand ) )
+ return MIstatus::failure;
+ }
+ }
+
+ // Check for invalid (removed) threads
+ CMICmnLLDBDebugSessionInfo::VecActiveThreadId_t::const_iterator it = CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.begin();
+ while( it != CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.end() )
+ {
+ const MIuint nThreadId = *it;
+ lldb::SBThread thread = rProcess.GetThreadAtIndex( nThreadId );
+ if( !thread.IsValid() )
+ {
+ // Form MI "=thread-exited,id=\"%ld\",group-id=\"i1\""
+ const CMIUtilString strValue( CMIUtilString::Format( "%ld", thread.GetIndexID() ) );
+ const CMICmnMIValueConst miValueConst( strValue );
+ const CMICmnMIValueResult miValueResult( "id", miValueConst );
+ CMICmnMIOutOfBandRecord miOutOfBand( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadExited, miValueResult );
+ const CMICmnMIValueConst miValueConst2( "i1" );
+ const CMICmnMIValueResult miValueResult2( "group-id", miValueConst2 );
+ bOk = miOutOfBand.Add( miValueResult2 );
+ bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBand );
+ if( !bOk )
+ return MIstatus::failure;
+ }
+
+ // Next
+ ++it;
+ }
+
+ return TextToStdout( "(gdb)" );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Take a fully formed MI result record and send to the stdout stream.
+// Also output to the MI Log file.
+// Type: Method.
+// Args: vrMiResultRecord - (R) MI result record object.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::MiResultRecordToStdout( const CMICmnMIResultRecord & vrMiResultRecord )
+{
+ return TextToStdout( vrMiResultRecord.GetString() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Take a fully formed MI Out-of-band record and send to the stdout stream.
+// Also output to the MI Log file.
+// Type: Method.
+// Args: vrMiOutOfBandRecord - (R) MI Out-of-band record object.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::MiOutOfBandRecordToStdout( const CMICmnMIOutOfBandRecord & vrMiOutOfBandRecord )
+{
+ return TextToStdout( vrMiOutOfBandRecord.GetString() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Take a text data and send to the stdout stream. Also output to the MI Log
+// file.
+// Type: Method.
+// Args: vrTxt - (R) Text.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::TextToStdout( const CMIUtilString & vrTxt )
+{
+ return CMICmnStreamStdout::TextToStdout( vrTxt );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Take a text data and send to the stderr stream. Also output to the MI Log
+// file.
+// Type: Method.
+// Args: vrTxt - (R) Text.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBDebuggerHandleEvents::TextToStderr( const CMIUtilString & vrTxt )
+{
+ return CMICmnStreamStderr::TextToStderr( vrTxt );
+}
diff --git a/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h b/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h
new file mode 100644
index 000000000000..fdcb2ea4e147
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h
@@ -0,0 +1,97 @@
+//===-- MICmnLLDBDebuggerHandleEvents.h -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBDebuggerHandleEvents.h
+//
+// Overview: CMICmnLLDBDebuggerHandleEvents interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MICmnMIValueTuple.h"
+#include "MIUtilSingletonBase.h"
+
+// Declarations:
+class CMICmnLLDBDebugSessionInfo;
+class CMICmnMIResultRecord;
+class CMICmnStreamStdout;
+class CMICmnMIOutOfBandRecord;
+
+//++ ============================================================================
+// Details: MI class to take LLDB SBEvent objects, filter them and form
+// MI Out-of-band records from the information inside the event object.
+// These records are then pushed to stdout.
+// A singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 02/03/2014.
+// Changes: None.
+//--
+class CMICmnLLDBDebuggerHandleEvents
+: public CMICmnBase
+, public MI::ISingleton< CMICmnLLDBDebuggerHandleEvents >
+{
+ friend class MI::ISingleton< CMICmnLLDBDebuggerHandleEvents >;
+
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+ //
+ bool HandleEvent( const lldb::SBEvent & vEvent, bool & vrbHandledEvent, bool & vrbExitAppEvent );
+
+// Methods:
+private:
+ /* ctor */ CMICmnLLDBDebuggerHandleEvents( void );
+ /* ctor */ CMICmnLLDBDebuggerHandleEvents( const CMICmnLLDBDebuggerHandleEvents & );
+ void operator=( const CMICmnLLDBDebuggerHandleEvents & );
+ //
+ bool ChkForStateChanges( void );
+ bool GetProcessStdout( void );
+ bool GetProcessStderr( void );
+ bool HandleEventSBBreakPoint( const lldb::SBEvent & vEvent );
+ bool HandleEventSBBreakpointCmn( const lldb::SBEvent & vEvent );
+ bool HandleEventSBBreakpointAdded( const lldb::SBEvent & vEvent );
+ bool HandleEventSBBreakpointLocationsAdded( const lldb::SBEvent & vEvent );
+ bool HandleEventSBProcess( const lldb::SBEvent & vEvent, bool & vrbExitAppEvent );
+ bool HandleEventSBThread( const lldb::SBEvent & vEvent );
+ bool HandleEventSBThreadBitStackChanged( const lldb::SBEvent & vEvent );
+ bool HandleEventSBThreadSuspended( const lldb::SBEvent & vEvent );
+ bool HandleEventSBCommandInterpreter( const lldb::SBEvent & vEvent );
+ bool HandleProcessEventBroadcastBitStateChanged( const lldb::SBEvent & vEvent, bool & vrbExitAppEvent );
+ bool HandleProcessEventStateRunning( void );
+ bool HandleProcessEventStateExited( void );
+ bool HandleProcessEventStateStopped( bool & vwrbShouldBrk );
+ bool HandleProcessEventStopReasonTrace( void );
+ bool HandleProcessEventStopReasonBreakpoint( void );
+ bool HandleProcessEventStopSignal( bool & vwrbShouldBrk );
+ bool HandleProcessEventStateSuspended( const lldb::SBEvent & vEvent );
+ bool MiHelpGetCurrentThreadFrame( CMICmnMIValueTuple & vwrMiValueTuple );
+ bool MiResultRecordToStdout( const CMICmnMIResultRecord & vrMiResultRecord );
+ bool MiOutOfBandRecordToStdout( const CMICmnMIOutOfBandRecord & vrMiResultRecord );
+ bool MiStoppedAtBreakPoint( const MIuint64 vBrkPtId, const lldb::SBBreakpoint & vBrkPt );
+ bool TextToStdout( const CMIUtilString & vrTxt );
+ bool TextToStderr( const CMIUtilString & vrTxt );
+ bool UpdateSelectedThread( void );
+ bool ConvertPrintfCtrlCodeToString( const MIchar vCtrl, CMIUtilString & vwrStrEquivalent );
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnLLDBDebuggerHandleEvents( void );
+};
+
diff --git a/tools/lldb-mi/MICmnLLDBProxySBValue.cpp b/tools/lldb-mi/MICmnLLDBProxySBValue.cpp
new file mode 100644
index 000000000000..78ef76bf698f
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBProxySBValue.cpp
@@ -0,0 +1,153 @@
+//===-- MICmnLLDBProxySBValue.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBProxySBValue.cpp
+//
+// Overview: CMICmnLLDBProxySBValue implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#include <stdlib.h>
+
+// Third Party Headers:
+#include <lldb/API/SBError.h>
+
+// In-house headers:
+#include "MICmnLLDBProxySBValue.h"
+#include "MIUtilString.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the numerical value from the SBValue object. If the function fails
+// it could indicate the SBValue object does not represent an internal type.
+// Type: Static method.
+// Args: vrValue - (R) The SBValue object to get a value from.
+// vwValue - (W) The numerical value.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBProxySBValue::GetValueAsUnsigned( const lldb::SBValue & vrValue, MIuint64 & vwValue )
+{
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( vrValue );
+ bool bCompositeType = true;
+ MIuint64 nFailValue = 0;
+ MIuint64 nValue = rValue.GetValueAsUnsigned( nFailValue );
+ if( nValue == nFailValue )
+ {
+ nFailValue = 5; // Some arbitary number
+ nValue = rValue.GetValueAsUnsigned( nFailValue );
+ if( nValue != nFailValue )
+ {
+ bCompositeType = false;
+ vwValue = nValue;
+ }
+ }
+ else
+ {
+ bCompositeType = false;
+ vwValue = nValue;
+ }
+
+ return (bCompositeType ? MIstatus::failure : MIstatus::success);
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the numerical value from the SBValue object. If the function fails
+// it could indicate the SBValue object does not represent an internal type.
+// Type: Static method.
+// Args: vrValue - (R) The SBValue object to get a value from.
+// vwValue - (W) The numerical value.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnLLDBProxySBValue::GetValueAsSigned( const lldb::SBValue & vrValue, MIint64 & vwValue )
+{
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( vrValue );
+ bool bCompositeType = true;
+ MIuint64 nFailValue = 0;
+ MIuint64 nValue = rValue.GetValueAsSigned( nFailValue );
+ if( nValue == nFailValue )
+ {
+ nFailValue = 5; // Some arbitary number
+ nValue = rValue.GetValueAsSigned( nFailValue );
+ if( nValue != nFailValue )
+ {
+ bCompositeType = false;
+ vwValue = nValue;
+ }
+ }
+ else
+ {
+ bCompositeType = false;
+ vwValue = nValue;
+ }
+
+ return (bCompositeType ? MIstatus::failure : MIstatus::success);
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the NUL terminated string from the SBValue object if it of the type
+// unsigned char *.
+// Type: Static method.
+// Args: vrValue - (R) The SBValue object to get a value from.
+// vwCString - (W) The text data '\0' terminated.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed, not suitable type.
+// Throws: None.
+//--
+bool CMICmnLLDBProxySBValue::GetCString( const lldb::SBValue & vrValue, CMIUtilString & vwCString )
+{
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( vrValue );
+ const MIchar * pCType = rValue.GetTypeName();
+ if( pCType == nullptr )
+ return MIstatus::failure;
+
+ const MIchar * pType = "unsigned char *";
+ if( !CMIUtilString::Compare( pCType, pType ) )
+ return MIstatus::failure;
+
+ const CMIUtilString strAddr( rValue.GetValue() );
+ MIint64 nNum = 0;
+ if( !strAddr.ExtractNumber( nNum ) )
+ return MIstatus::failure;
+
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ lldb::SBProcess & rProcess = rSessionInfo.m_lldbProcess;
+ MIuint nBufferSize = 64;
+ bool bNeedResize = false;
+ MIchar * pBuffer = static_cast< MIchar * >( ::malloc( nBufferSize ) );
+ do
+ {
+ lldb::SBError error;
+ const size_t nReadSize = rProcess.ReadCStringFromMemory( (lldb::addr_t) nNum, pBuffer, nBufferSize, error );
+ if( nReadSize == (nBufferSize - 1) )
+ {
+ bNeedResize = true;
+ nBufferSize = nBufferSize << 1;
+ pBuffer = static_cast< MIchar * >( ::realloc( pBuffer, nBufferSize ) );
+ }
+ else
+ bNeedResize = false;
+ }
+ while( bNeedResize );
+
+ vwCString = pBuffer;
+ free( (void *) pBuffer );
+
+ return MIstatus::success;
+}
+
diff --git a/tools/lldb-mi/MICmnLLDBProxySBValue.h b/tools/lldb-mi/MICmnLLDBProxySBValue.h
new file mode 100644
index 000000000000..7e743cdb7eaf
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBProxySBValue.h
@@ -0,0 +1,47 @@
+//===-- MICmnLLDBProxySBValue.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBProxySBValue.h
+//
+// Overview: CMICmnLLDBProxySBValue interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third Party Headers:
+#include <lldb/API/SBValue.h>
+
+// In-house headers:
+#include "MIDataTypes.h"
+
+// Declerations:
+class CMIUtilString;
+
+//++ ============================================================================
+// Details: MI proxy wrapper class to lldb::SBValue. The class provides functionality
+// to assist in the use of SBValue's parculiar function usage.
+// Gotchas: None.
+// Authors: Illya Rudkin 03/04/2014.
+// Changes: None.
+//--
+class CMICmnLLDBProxySBValue
+{
+// Statics:
+public:
+ static bool GetValueAsSigned( const lldb::SBValue & vrValue, MIint64 & vwValue );
+ static bool GetValueAsUnsigned( const lldb::SBValue & vrValue, MIuint64 & vwValue );
+ static bool GetCString( const lldb::SBValue & vrValue, CMIUtilString & vwCString );
+};
diff --git a/tools/lldb-mi/MICmnLLDBUtilSBValue.cpp b/tools/lldb-mi/MICmnLLDBUtilSBValue.cpp
new file mode 100644
index 000000000000..004be071260a
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBUtilSBValue.cpp
@@ -0,0 +1,324 @@
+//===-- MICmnLLDBUtilSBValue.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBUtilSBValue.cpp
+//
+// Overview: CMICmnLLDBUtilSBValue implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnLLDBUtilSBValue.h"
+#include "MIUtilString.h"
+#include "MICmnLLDBDebugSessionInfo.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBUtilSBValue constructor.
+// Type: Method.
+// Args: vrValue - (R) The LLDb value object.
+// vbHandleCharType - (R) True = Yes return text molding to char type,
+// False = just return data.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBUtilSBValue::CMICmnLLDBUtilSBValue( const lldb::SBValue & vrValue, const bool vbHandleCharType /* = false */ )
+: m_rValue( const_cast< lldb::SBValue & >( vrValue ) )
+, m_pUnkwn( "??" )
+, m_bHandleCharType( vbHandleCharType )
+{
+ m_bValidSBValue = m_rValue.IsValid();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLLDBUtilSBValue destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLLDBUtilSBValue::~CMICmnLLDBUtilSBValue( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve from the LLDB SB Value object the name of the variable. If the name
+// is invalid (or the SBValue object invalid) then "??" is returned.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Name of the variable or "??" for unknown.
+// Throws: None.
+//--
+CMIUtilString CMICmnLLDBUtilSBValue::GetName( void ) const
+{
+ const MIchar * pName = m_bValidSBValue ? m_rValue.GetName() : nullptr;
+ const CMIUtilString text( (pName != nullptr) ? pName : m_pUnkwn );
+
+ return text;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve from the LLDB SB Value object the value of the variable described in
+// text. If the value is invalid (or the SBValue object invalid) then "??" is
+// returned.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Text description of the variable's value or "??".
+// Throws: None.
+//--
+CMIUtilString CMICmnLLDBUtilSBValue::GetValue( void ) const
+{
+ CMIUtilString text;
+
+ if( m_bHandleCharType && IsCharType() )
+ {
+ const lldb::addr_t addr = m_rValue.GetLoadAddress();
+ text = CMIUtilString::Format( "0x%08x", addr );
+ const CMIUtilString cString( GetValueCString() );
+ if( !cString.empty() )
+ text += CMIUtilString::Format( " %s", cString.c_str() );
+ }
+ else
+ {
+ const MIchar * pValue = m_bValidSBValue ? m_rValue.GetValue() : nullptr;
+ text = (pValue != nullptr) ? pValue : m_pUnkwn;
+ }
+
+ return text;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: If the LLDB SB Value object is a char type then form the text data string
+// otherwise return nothing. m_bHandleCharType must be true to return text data
+// if any.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Text description of the variable's value.
+// Throws: None.
+//--
+CMIUtilString CMICmnLLDBUtilSBValue::GetValueCString( void ) const
+{
+ CMIUtilString text;
+
+ if( m_bHandleCharType && IsCharType() )
+ {
+ text = ReadCStringFromHostMemory( m_rValue );
+ }
+
+ return text;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the flag stating whether this value object is a char type or some
+// other type. Char type can be signed or unsigned.
+// Type: Method.
+// Args: None.
+// Return: bool - True = Yes is a char type, false = some other type.
+// Throws: None.
+//--
+bool CMICmnLLDBUtilSBValue::IsCharType( void ) const
+{
+ const MIchar * pName = m_rValue.GetName(); MIunused( pName );
+ const lldb::BasicType eType = m_rValue.GetType().GetBasicType();
+ return ((eType == lldb::eBasicTypeChar) ||
+ (eType == lldb::eBasicTypeSignedChar) ||
+ (eType == lldb::eBasicTypeUnsignedChar) );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the flag stating whether any child value object of *this object is a
+// char type or some other type. Returns false if there are not children. Char
+// type can be signed or unsigned.
+// Type: Method.
+// Args: None.
+// Return: bool - True = Yes is a char type, false = some other type.
+// Throws: None.
+//--
+bool CMICmnLLDBUtilSBValue::IsChildCharType( void ) const
+{
+ const MIuint nChildren = m_rValue.GetNumChildren();
+
+ // Is it a basic type
+ if( nChildren == 0 )
+ return false;
+
+ // Is it a composite type
+ if( nChildren > 1 )
+ return false;
+
+ lldb::SBValue member = m_rValue.GetChildAtIndex( 0 );
+ const CMICmnLLDBUtilSBValue utilValue( member );
+ return utilValue.IsCharType();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the C string data for a child of char type (one and only child) for
+// the parent value object. If the child is not a char type or the parent has
+// more than one child then an empty string is returned. Char type can be
+// signed or unsigned.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Text description of the variable's value.
+// Throws: None.
+//--
+CMIUtilString CMICmnLLDBUtilSBValue::GetChildValueCString( void ) const
+{
+ CMIUtilString text;
+ const MIuint nChildren = m_rValue.GetNumChildren();
+
+ // Is it a basic type
+ if( nChildren == 0 )
+ return text;
+
+ // Is it a composite type
+ if( nChildren > 1 )
+ return text;
+
+ lldb::SBValue member = m_rValue.GetChildAtIndex( 0 );
+ const CMICmnLLDBUtilSBValue utilValue( member );
+ if( m_bHandleCharType && utilValue.IsCharType() )
+ {
+ text = ReadCStringFromHostMemory( member );
+ }
+
+ return text;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the C string data of value object by read the memory where the
+// variable is held.
+// Type: Method.
+// Args: vrValueObj - (R) LLDB SBValue variable object.
+// Return: CMIUtilString - Text description of the variable's value.
+// Throws: None.
+//--
+CMIUtilString CMICmnLLDBUtilSBValue::ReadCStringFromHostMemory( const lldb::SBValue & vrValueObj ) const
+{
+ CMIUtilString text;
+
+ lldb::SBValue & rValue = const_cast< lldb::SBValue & >( vrValueObj );
+ const lldb::addr_t addr = rValue.GetLoadAddress();
+ CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() );
+ const MIuint nBytes( 128 );
+ const MIchar * pBufferMemory = new MIchar[ nBytes ];
+ lldb::SBError error;
+ const MIuint64 nReadBytes = rSessionInfo.m_lldbProcess.ReadMemory( addr, (void *) pBufferMemory, nBytes, error ); MIunused( nReadBytes );
+ text = CMIUtilString::Format( "\\\"%s\\\"", pBufferMemory );
+ delete [] pBufferMemory;
+
+ return text;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the state of the value object's name.
+// Type: Method.
+// Args: None.
+// Return: bool - True = yes name is indeterminate, false = name is valid.
+// Throws: None.
+//--
+bool CMICmnLLDBUtilSBValue::IsNameUnknown( void ) const
+{
+ const CMIUtilString name( GetName() );
+ return (name == m_pUnkwn);
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the state of the value object's value data.
+// Type: Method.
+// Args: None.
+// Return: bool - True = yes value is indeterminate, false = value valid.
+// Throws: None.
+//--
+bool CMICmnLLDBUtilSBValue::IsValueUnknown( void ) const
+{
+ const CMIUtilString value( GetValue() );
+ return (value == m_pUnkwn);
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the value object's type name if valid.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - The type name or "??".
+// Throws: None.
+//--
+CMIUtilString CMICmnLLDBUtilSBValue::GetTypeName( void ) const
+{
+ const MIchar * pName = m_bValidSBValue ? m_rValue.GetTypeName() : nullptr;
+ const CMIUtilString text( (pName != nullptr) ? pName : m_pUnkwn );
+
+ return text;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the value object's display type name if valid.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - The type name or "??".
+// Throws: None.
+//--
+CMIUtilString CMICmnLLDBUtilSBValue::GetTypeNameDisplay( void ) const
+{
+ const MIchar * pName = m_bValidSBValue ? m_rValue.GetDisplayTypeName() : nullptr;
+ const CMIUtilString text( (pName != nullptr) ? pName : m_pUnkwn );
+
+ return text;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve whether the value object's is valid or not.
+// Type: Method.
+// Args: None.
+// Return: bool - True = valid, false = not valid.
+// Throws: None.
+//--
+bool CMICmnLLDBUtilSBValue::IsValid( void ) const
+{
+ return m_bValidSBValue;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the value object' has a name. A value object can be valid but still
+// have no name which suggest it is not a variable.
+// Type: Method.
+// Args: None.
+// Return: bool - True = valid, false = not valid.
+// Throws: None.
+//--
+bool CMICmnLLDBUtilSBValue::HasName( void ) const
+{
+ bool bHasAName = false;
+
+ const MIchar * pName = m_bValidSBValue ? m_rValue.GetDisplayTypeName() : nullptr;
+ if( pName != nullptr )
+ {
+ bHasAName = (CMIUtilString( pName ).length() > 0);
+ }
+
+ return bHasAName;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine if the value object' respresents a LLDB variable i.e. "$0".
+// Type: Method.
+// Args: None.
+// Return: bool - True = Yes LLDB variable, false = no.
+// Throws: None.
+//--
+bool CMICmnLLDBUtilSBValue::IsLLDBVariable( void ) const
+{
+ return (GetName().at( 0 ) == '$' );
+}
+
+
diff --git a/tools/lldb-mi/MICmnLLDBUtilSBValue.h b/tools/lldb-mi/MICmnLLDBUtilSBValue.h
new file mode 100644
index 000000000000..d2c1876c44b7
--- /dev/null
+++ b/tools/lldb-mi/MICmnLLDBUtilSBValue.h
@@ -0,0 +1,71 @@
+//===-- MICmnLLDBUtilSBValue.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLLDBUtilSBValue.h
+//
+// Overview: CMICmnLLDBUtilSBValue interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third Party Headers:
+#include <lldb/API/SBValue.h>
+
+// In-house headers:
+#include "MIDataTypes.h"
+
+// Declerations:
+class CMIUtilString;
+
+//++ ============================================================================
+// Details: Utility helper class to lldb::SBValue. Using a lldb::SBValue extract
+// value object information to help form verbose debug information.
+// Gotchas: None.
+// Authors: Illya Rudkin 08/07/2014.
+// Changes: None.
+//--
+class CMICmnLLDBUtilSBValue
+{
+// Methods:
+public:
+ /* ctor */ CMICmnLLDBUtilSBValue( const lldb::SBValue & vrValue, const bool vbHandleCharType = false );
+ /* dtor */ ~CMICmnLLDBUtilSBValue( void );
+ //
+ CMIUtilString GetName( void ) const;
+ CMIUtilString GetValue( void ) const;
+ CMIUtilString GetValueCString( void ) const;
+ CMIUtilString GetChildValueCString( void ) const;
+ CMIUtilString GetTypeName( void ) const;
+ CMIUtilString GetTypeNameDisplay( void ) const;
+ bool IsCharType( void ) const;
+ bool IsChildCharType( void ) const;
+ bool IsLLDBVariable( void ) const;
+ bool IsNameUnknown( void ) const;
+ bool IsValueUnknown( void ) const;
+ bool IsValid( void ) const;
+ bool HasName( void ) const;
+
+// Methods:
+private:
+ CMIUtilString ReadCStringFromHostMemory( const lldb::SBValue & vrValueObj ) const;
+
+// Attributes:
+private:
+ lldb::SBValue & m_rValue;
+ const MIchar * m_pUnkwn;
+ bool m_bValidSBValue; // True = SBValue is a valid object, false = not valid.
+ bool m_bHandleCharType; // True = Yes return text molding to char type, false = just return data.
+};
diff --git a/tools/lldb-mi/MICmnLog.cpp b/tools/lldb-mi/MICmnLog.cpp
new file mode 100644
index 000000000000..4ccbd3ef992c
--- /dev/null
+++ b/tools/lldb-mi/MICmnLog.cpp
@@ -0,0 +1,355 @@
+//===-- MICmnLog.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLog.cpp
+//
+// Overview: CMICmnLog implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnLog.h"
+#include "MICmnLogMediumFile.h"
+#include "MIDriverMgr.h"
+#include "MICmnResources.h"
+#include "MIUtilDateTimeStd.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLog constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLog::CMICmnLog( void )
+: m_bEnabled( false )
+, m_bInitializingATM( false )
+{
+ // Do not use this constructor, use Initialize()
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLog destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLog::~CMICmnLog( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this Logger.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLog::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ ClrErrorDescription();
+
+ // Mediums set inside because explicitly initing in MIDriverMain.cpp causes compile errors with CAtlFile
+ CMICmnLogMediumFile & rFileLog( CMICmnLogMediumFile::Instance() );
+ bool bOk = RegisterMedium( rFileLog );
+ bOk = bOk && SetEnabled( true );
+ if( bOk )
+ {
+ // Set the Log trace file's header
+ const CMIUtilString & rCR( rFileLog.GetLineReturn() );
+ CMIUtilDateTimeStd date;
+ CMIUtilString msg;
+ msg = CMIUtilString::Format( "%s\n", CMIDriverMgr::Instance().GetAppVersion().c_str() );
+ CMIUtilString logHdr( msg );
+ msg = CMIUtilString::Format( MIRSRC( IDS_LOG_MSG_CREATION_DATE ), date.GetDate().c_str(), date.GetTime().c_str(), rCR.c_str() );
+ logHdr += msg;
+ msg = CMIUtilString::Format( MIRSRC( IDS_LOG_MSG_FILE_LOGGER_PATH ), rFileLog.GetFileNamePath().c_str(), rCR.c_str() );
+ logHdr += msg;
+
+ bOk = rFileLog.SetHeaderTxt( logHdr );
+
+ // Note log file medium's status is not available until we write at least once to the file (so just write the title 1st line)
+ m_bInitializingATM = true;
+ CMICmnLog::WriteLog( "." );
+ if( !rFileLog.IsOk() )
+ {
+ const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LOG_ERR_FILE_LOGGER_DISABLED ), rFileLog.GetErrorDescription().c_str() ) );
+ CMICmnLog::WriteLog( msg );
+ }
+ m_bInitializingATM = false;
+ }
+
+ m_bInitialized = bOk;
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this Logger.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLog::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ ClrErrorDescription();
+
+ const bool bOk = UnregisterMediumAll();
+
+ m_bInitialized = bOk;
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Enabled or disable *this Logger from writing any data to registered clients.
+// Type: Method.
+// Args: vbYes - (R) True = Logger enabled, false = disabled.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLog::SetEnabled( const bool vbYes )
+{
+ m_bEnabled = vbYes;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve state whether *this Logger is enabled writing data to registered clients.
+// Type: Method.
+// Args: None.
+// Return: True = Logger enable.
+// False = disabled.
+// Throws: None.
+//--
+bool CMICmnLog::GetEnabled( void ) const
+{
+ return m_bEnabled;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Unregister all the Mediums registered with *this Logger.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLog::UnregisterMediumAll( void )
+{
+ MapMediumToName_t::const_iterator it = m_mapMediumToName.begin();
+ for( ; it != m_mapMediumToName.end( ); it++ )
+ {
+ IMedium * pMedium = (*it).first;
+ pMedium->Shutdown();
+ }
+
+ m_mapMediumToName.clear();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Register a Medium with *this Logger.
+// Type: Method.
+// Args: vrMedium - (R) The medium to register.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLog::RegisterMedium( const IMedium & vrMedium )
+{
+ if( HaveMediumAlready( vrMedium ) )
+ return MIstatus::success;
+
+ IMedium * pMedium = const_cast< IMedium * >( &vrMedium );
+ if( !pMedium->Initialize() )
+ {
+ const CMIUtilString & rStrMedName( pMedium->GetName() );
+ const CMIUtilString & rStrMedErr( pMedium->GetError() );
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LOG_MEDIUM_ERR_INIT ), rStrMedName.c_str(), rStrMedErr.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ MapPairMediumToName_t pr( pMedium, pMedium->GetName() );
+ m_mapMediumToName.insert( pr );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Query the Logger to see if a medium is already registered.
+// Type: Method.
+// Args: vrMedium - (R) The medium to query.
+// Return: True - registered.
+// False - not registered.
+// Throws: None.
+//--
+bool CMICmnLog::HaveMediumAlready( const IMedium & vrMedium ) const
+{
+ IMedium * pMedium = const_cast< IMedium * >( &vrMedium );
+ const MapMediumToName_t::const_iterator it = m_mapMediumToName.find( pMedium );
+ if( it != m_mapMediumToName.end() )
+ return true;
+
+ return false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Unregister a medium from the Logger.
+// Type: Method.
+// Args: vrMedium - (R) The medium to unregister.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLog::UnregisterMedium( const IMedium & vrMedium )
+{
+ IMedium * pMedium = const_cast< IMedium * >( &vrMedium );
+ m_mapMediumToName.erase( pMedium );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The callee client uses this function to write to the Logger. The data to be
+// written is given out to all the mediums registered. The verbosity type parameter
+// indicates to the medium(s) the type of data or message given to it. The medium has
+// modes of verbosity and depending on the verbosity set determines which writes
+// go in to the logger.
+// The logger must be initialized successfully before a write to any registered
+// can be carried out.
+// Type: Method.
+// Args: vData - (R) The data to write to the logger.
+// veType - (R) Verbosity type.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLog::Write( const CMIUtilString & vData, const ELogVerbosity veType )
+{
+ if( !m_bInitialized && !m_bInitializingATM )
+ return MIstatus::success;
+ if( m_bRecursiveDive )
+ return MIstatus::success;
+ if( !m_bEnabled )
+ return MIstatus::success;
+
+ m_bRecursiveDive = true;
+
+ MIuint cnt = 0;
+ MIuint cntErr = 0;
+ {
+ MapMediumToName_t::const_iterator it = m_mapMediumToName.begin();
+ while( it != m_mapMediumToName.end() )
+ {
+ IMedium * pMedium = (*it).first;
+ const CMIUtilString & rNameMedium = (*it).second; MIunused( rNameMedium );
+ if( pMedium->Write( vData, veType ) )
+ cnt++;
+ else
+ cntErr++;
+
+ // Next
+ ++it;
+ }
+ }
+
+ bool bOk = MIstatus::success;
+ const MIuint mediumCnt = m_mapMediumToName.size();
+ if( (cnt == 0) && (mediumCnt > 0) )
+ {
+ SetErrorDescription( MIRSRC( IDS_LOG_MEDIUM_ERR_WRITE_ANY ) );
+ bOk = MIstatus::failure;
+ }
+ if( bOk && (cntErr != 0) )
+ {
+ SetErrorDescription( MIRSRC( IDS_LOG_MEDIUM_ERR_WRITE_MEDIUMFAIL ) );
+ bOk = MIstatus::failure;
+ }
+
+ m_bRecursiveDive = false;
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Short cut function call to write only to the Log file.
+// The logger must be initialized successfully before a write to any registered
+// can be carried out.
+// Type: Static.
+// Args: vData - (R) The data to write to the logger.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLog::WriteLog( const CMIUtilString & vData )
+{
+ return CMICmnLog::Instance().Write( vData, CMICmnLog::eLogVerbosity_Log );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve a string detailing the last error.
+// Type: Method.
+// Args: None,
+// Return: CMIUtilString.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnLog::GetErrorDescription( void ) const
+{
+ return m_strMILastErrorDescription;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set the internal description of the last error.
+// Type: Method.
+// Args: (R) String containing a description of the last error.
+// Return: None.
+// Throws: None.
+//--
+void CMICmnLog::SetErrorDescription( const CMIUtilString & vrTxt ) const
+{
+ m_strMILastErrorDescription = vrTxt;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Clear the last error.
+// Type: None.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMICmnLog::ClrErrorDescription( void ) const
+{
+ m_strMILastErrorDescription = CMIUtilString( "" );
+}
diff --git a/tools/lldb-mi/MICmnLog.h b/tools/lldb-mi/MICmnLog.h
new file mode 100644
index 000000000000..57288237840d
--- /dev/null
+++ b/tools/lldb-mi/MICmnLog.h
@@ -0,0 +1,143 @@
+//===-- MICmnLog.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLog.h
+//
+// Overview: CMICmnLog interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <map>
+
+// In-house headers:
+#include "MIUtilString.h"
+#include "MICmnBase.h"
+#include "MIUtilSingletonBase.h"
+
+//++ ============================================================================
+// Details: MI common code implementation class. Handle application trace
+// activity logging. Medium objects derived from the Medium abstract
+/// class are registered with this loggor. The function Write is called
+// by a client callee to log information. That information is given to
+// registered relevant mediums. The medium file is registered during
+// *this logs initialization so it will always have a file log for the
+// application.
+// Singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 01/02/2012.
+// Changes: None.
+//--
+class CMICmnLog : public MI::ISingleton< CMICmnLog >
+{
+ friend MI::ISingleton< CMICmnLog >;
+
+// Enumeration:
+public:
+ //++
+ // Description: Data given to the Logger can be of serveral types. The Logger can be
+ // set at levels of verbosity. Can determine how data is sent to one or
+ // mediums.
+ //--
+ enum ELogVerbosity
+ { // Descriptions of what 'may' occur, depends ultimately on the medium itself. See the medium.
+ eLogVerbosity_FnTrace = 0x00000004, // Debug function stack call tracing
+ eLogVerbosity_DbgOp = 0x00000008, // Send a string to the debugguer for display (not implemented)
+ eLogVerbosity_ClientMsg = 0x00000010, // A client using MI can insert messages into the log (not implemented)
+ eLogVerbosity_Log = 0x00000020 // Send to only the Log file.
+ };
+
+// Class:
+public:
+ //++
+ // Description: Register a medium derived from this interface which will be
+ // called writing log trace data i.e. a file or a console.
+ // Medium objects registered are not owned by *this logger.
+ //--
+ class IMedium
+ {
+ public:
+ virtual bool Initialize( void ) = 0;
+ virtual const CMIUtilString & GetName( void ) const = 0;
+ virtual bool Write( const CMIUtilString & vData, const ELogVerbosity veType ) = 0;
+ virtual const CMIUtilString & GetError( void ) const = 0;
+ virtual bool Shutdown( void ) = 0;
+
+ // Not part of the interface, ignore
+ //AD: This virtual destructor seems to hit a bug in the stdlib
+ // where vector delete is incorrectly called. Workaround is
+ // to comment this out while I investigate.
+ /* dtor */ virtual ~IMedium( void ) {}
+ };
+
+// Statics:
+public:
+ static bool WriteLog( const CMIUtilString & vData );
+
+// Methods:
+public:
+ bool RegisterMedium( const IMedium & vrMedium );
+ bool UnregisterMedium( const IMedium & vrMedium );
+ bool Write( const CMIUtilString & vData, const ELogVerbosity veType );
+ bool SetEnabled( const bool vbYes );
+ bool GetEnabled( void ) const;
+
+ // MI common object handling - duplicate of CMICmnBase functions, necessary for LINUX build
+ // Done to stop locking on object construction init circular dependency.
+ const CMIUtilString & GetErrorDescription( void ) const;
+ void SetErrorDescription( const CMIUtilString & vrTxt ) const;
+ void ClrErrorDescription( void ) const;
+
+// Overridden:
+public:
+ // From MI::ISingleton
+ virtual bool Initialize( void );
+ virtual bool Shutdown( void );
+
+// Methods:
+private:
+ /* ctor */ CMICmnLog( void );
+ /* ctor */ CMICmnLog( const CMICmnLog & );
+ void operator=( const CMICmnLog & );
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnLog( void );
+
+// Typedef:
+private:
+ typedef std::map< IMedium *, CMIUtilString > MapMediumToName_t;
+ typedef std::pair< IMedium *, CMIUtilString > MapPairMediumToName_t;
+
+// Methods:
+private:
+ bool HaveMediumAlready( const IMedium & vrMedium ) const;
+ bool UnregisterMediumAll( void );
+
+// Attributes:
+private:
+ bool m_bRecursiveDive; // True = yes recursive, false = no
+ MapMediumToName_t m_mapMediumToName;
+ bool m_bEnabled; // True = Logger enabled for writing to mediums, false = medium not written to
+ bool m_bInitializingATM; // True = Yes in process of initing *this logger, false = not initing
+ //
+ // MI common object handling - duplicate of CMICmnBase functions, necessary for LINUX build
+ bool m_bInitialized; // True = yes successfully initialized, false = no yet or failed
+ mutable CMIUtilString m_strMILastErrorDescription;
+ MIint m_clientUsageRefCnt; // Count of client using *this object so not shutdown() object to early
+};
diff --git a/tools/lldb-mi/MICmnLogMediumFile.cpp b/tools/lldb-mi/MICmnLogMediumFile.cpp
new file mode 100644
index 000000000000..228a9cf4b3be
--- /dev/null
+++ b/tools/lldb-mi/MICmnLogMediumFile.cpp
@@ -0,0 +1,420 @@
+//===-- MICmnLogMediumFile.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLogMediumFile.cpp
+//
+// Overview: CMICmnLogMediumFile implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnLogMediumFile.h"
+#include "MICmnResources.h"
+#if defined( _MSC_VER )
+ #include "MIUtilSystemWindows.h"
+#elif defined( __FreeBSD__ ) || defined( __linux__ )
+ #include "MIUtilSystemLinux.h"
+#elif defined( __APPLE__ )
+ #include "MIUtilSystemOsx.h"
+#endif // defined( _MSC_VER )
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLogMediumFile constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLogMediumFile::CMICmnLogMediumFile( void )
+: m_constThisMediumName( MIRSRC( IDS_MEDIUMFILE_NAME ) )
+, m_constMediumFileName( "lldb-mi-log.txt" )
+, m_fileNamePath( MIRSRC( IDS_MEDIUMFILE_ERR_INVALID_PATH ) )
+, m_eVerbosityType( CMICmnLog::eLogVerbosity_Log )
+, m_strDate( CMIUtilDateTimeStd().GetDate() )
+, m_fileHeaderTxt( MIRSRC( IDS_MEDIUMFILE_ERR_FILE_HEADER ) )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnLogMediumFile destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnLogMediumFile::~CMICmnLogMediumFile( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get the singleton instance of *this class.
+// Type: Static.
+// Args: None.
+// Return: CMICmnLogMediumFile - Reference to *this object.
+// Throws: None.
+//--
+CMICmnLogMediumFile & CMICmnLogMediumFile::Instance( void )
+{
+ static CMICmnLogMediumFile instance;
+
+ return instance;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize setup *this medium ready for use.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLogMediumFile::Initialize( void )
+{
+ m_bInitialized = FileFormFileNamePath();
+
+ return m_bInitialized;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Unbind detach or release resources used by *this medium.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+bool CMICmnLogMediumFile::Shutdown( void )
+{
+ if( m_bInitialized )
+ {
+ m_bInitialized = false;
+ m_file.Close();
+ }
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the name of *this medium.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString - Text data.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnLogMediumFile::GetName( void ) const
+{
+ return m_constThisMediumName;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The callee client calls the write function on the Logger. The data to be
+// written is given out to all the mediums registered. The verbosity type parameter
+// indicates to the medium the type of data or message given to it. The medium has
+// modes of verbosity and depending on the verbosity set determines which data is
+// sent to the medium's output.
+// Type: Method.
+// Args: vData - (R) The data to write to the logger.
+// veType - (R) Verbosity type.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLogMediumFile::Write( const CMIUtilString & vData, const CMICmnLog::ELogVerbosity veType )
+{
+ if( m_bInitialized && m_file.IsOk() )
+ {
+ const bool bDoWrite = (m_eVerbosityType & veType);
+ if( bDoWrite )
+ {
+ bool bNewCreated = false;
+ bool bOk = m_file.CreateWrite( m_fileNamePath, bNewCreated );
+ if( bOk )
+ {
+ if( bNewCreated )
+ bOk = FileWriteHeader();
+ bOk = bOk && FileWriteEnglish( MassagedData( vData, veType ) );
+ }
+ return bOk;
+ }
+ }
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve *this medium's last error condition.
+// Type: Method.
+// Args: None.
+// Return: CString & - Text description.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnLogMediumFile::GetError( void ) const
+{
+ return m_strMILastErrorDescription;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set the verbosity mode for this medium.
+// Type: Method.
+// Args: veType - (R) Mask value.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLogMediumFile::SetVerbosity( const MIuint veType )
+{
+ m_eVerbosityType = veType;
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get the verbosity mode for this medium.
+// Type: Method.
+// Args: veType - (R) Mask value.
+// Return: CMICmnLog::ELogVerbosity - Mask value.
+// Throws: None.
+//--
+MIuint CMICmnLogMediumFile::GetVerbosity( void ) const
+{
+ return m_eVerbosityType;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Write data to a file English font.
+// Type: Method.
+// Args: vData - (R) The data to write to the logger.
+// Return: None.
+// Throws: None.
+//--
+bool CMICmnLogMediumFile::FileWriteEnglish( const CMIUtilString & vData )
+{
+ return m_file.Write( vData );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine and form the medium file's directory path and name.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLogMediumFile::FileFormFileNamePath( void )
+{
+ ClrErrorDescription();
+
+ m_fileNamePath = MIRSRC( IDS_MEDIUMFILE_ERR_INVALID_PATH );
+
+ CMIUtilString strPathName;
+ if( CMIUtilSystem().GetLogFilesPath( strPathName ) )
+ {
+ const CMIUtilString strPath = CMIUtilFileStd().StripOffFileName( strPathName );
+
+ // ToDo: Review this LINUX log file quick fix so not hidden
+ // AD:
+ // Linux was creating a log file here called '.\log.txt'. The '.' on linux
+ // signifies that this file is 'hidden' and not normally visible. A quick fix
+ // is to remove the path component all together. Linux also normally uses '/'
+ // as directory separators, again leading to the problem of the hidden log.
+#if defined ( _MSC_VER )
+ m_fileNamePath = CMIUtilString::Format( "%s\\%s", strPath.c_str(), m_constMediumFileName.c_str() );
+#else
+ m_fileNamePath = CMIUtilString::Format( "%s", m_constMediumFileName.c_str() );
+#endif // defined ( _MSC_VER )
+
+ return MIstatus::success;
+ }
+
+ SetErrorDescription( MIRSRC( IDE_MEDIUMFILE_ERR_GET_FILE_PATHNAME_SYS ) );
+
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the medium file's directory path and name.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - File path.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnLogMediumFile::GetFileNamePath( void ) const
+{
+ return m_fileNamePath;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the medium file's name.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - File name.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnLogMediumFile::GetFileName( void ) const
+{
+ return m_constMediumFileName;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Massage the data to behave correct when submitted to file. Insert extra log
+// specific text. The veType is there to allow in the future to parse the log and
+// filter in out specific types of message to make viewing the log more manageable.
+// Type: Method.
+// Args: vData - (R) Raw data.
+// veType - (R) Message type.
+// Return: CMIUtilString - Massaged data.
+// Throws: None.
+//--
+CMIUtilString CMICmnLogMediumFile::MassagedData( const CMIUtilString & vData, const CMICmnLog::ELogVerbosity veType )
+{
+ const CMIUtilString strCr( "\n" );
+ CMIUtilString data;
+ const MIchar verbosityCode( ConvertLogVerbosityTypeToId( veType ) );
+ const CMIUtilString dt( CMIUtilString::Format( "%s %s", m_strDate.c_str(), m_dateTime.GetTime().c_str() ) );
+
+ data = CMIUtilString::Format( "%c,%s,%s", verbosityCode, dt.c_str(), vData.c_str() );
+ data = ConvertCr( data );
+
+ // Look for EOL...
+ const MIint pos = vData.rfind( strCr );
+ if( pos == (MIint) vData.size() )
+ return data;
+
+ // ... did not have an EOL so add one
+ data += GetLineReturn();
+
+ return data;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Convert the Log's verbosity type number into a single char character.
+// Type: Method.
+// Args: veType - (R) Message type.
+// Return: wchar_t - A letter.
+// Throws: None.
+//--
+MIchar CMICmnLogMediumFile::ConvertLogVerbosityTypeToId( const CMICmnLog::ELogVerbosity veType ) const
+{
+ MIchar c = 0;
+ if( veType != 0 )
+ {
+ MIuint cnt = 0;
+ MIuint number( veType );
+ while( 1 != number )
+ {
+ number = number >> 1;
+ ++cnt;
+ }
+ c = 'A' + cnt;
+ }
+ else
+ {
+ c = '*';
+ }
+
+ return c;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve state of whether the file medium is ok.
+// Type: Method.
+// Args: None.
+// Return: True - file ok.
+// False - file has a problem.
+// Throws: None.
+//--
+bool CMICmnLogMediumFile::IsOk( void ) const
+{
+ return m_file.IsOk();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Status on the file log medium existing already.
+// Type: Method.
+// Args: None.
+// Return: True - Exists.
+// False - Not found.
+// Throws: None.
+//--
+bool CMICmnLogMediumFile::IsFileExist( void ) const
+{
+ return m_file.IsFileExist( GetFileNamePath() );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Write the header text the logger file.
+// Type: Method.
+// Args: vText - (R) Text.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLogMediumFile::FileWriteHeader( void )
+{
+ return FileWriteEnglish( ConvertCr( m_fileHeaderTxt ) );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Convert any carriage line returns to be compatible with the platform the
+// Log fiel is being written to.
+// Type: Method.
+// Args: vData - (R) Text data.
+// Return: CMIUtilString - Converted string data.
+// Throws: None.
+//--
+CMIUtilString CMICmnLogMediumFile::ConvertCr( const CMIUtilString & vData ) const
+{
+ const CMIUtilString strCr( "\n" );
+ const CMIUtilString & rCrCmpat( GetLineReturn() );
+
+ if( strCr == rCrCmpat )
+ return vData;
+
+ const MIuint nSizeCmpat( rCrCmpat.size() );
+ const MIuint nSize( strCr.size() );
+ CMIUtilString strConv( vData );
+ MIint pos = strConv.find( strCr );
+ while( pos != (MIint) CMIUtilString::npos )
+ {
+ strConv.replace( pos, nSize, rCrCmpat );
+ pos = strConv.find( strCr, pos + nSizeCmpat );
+ }
+
+ return strConv;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set the header text that is written to the logger file at the begining.
+// Type: Method.
+// Args: vText - (R) Text.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnLogMediumFile::SetHeaderTxt( const CMIUtilString & vText )
+{
+ m_fileHeaderTxt = vText;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the file current carriage line return characters used.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - Text.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnLogMediumFile::GetLineReturn( void ) const
+{
+ return m_file.GetLineReturn();
+}
diff --git a/tools/lldb-mi/MICmnLogMediumFile.h b/tools/lldb-mi/MICmnLogMediumFile.h
new file mode 100644
index 000000000000..affe24e09e57
--- /dev/null
+++ b/tools/lldb-mi/MICmnLogMediumFile.h
@@ -0,0 +1,96 @@
+//===-- MICmnLogMediumFile.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnLogMediumFile.h
+//
+// Overview: CMICmnLogMediumFile interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MIUtilFileStd.h"
+#include "MIUtilString.h"
+#include "MICmnBase.h"
+#include "MICmnLog.h"
+#include "MIUtilDateTimeStd.h"
+
+//++ ============================================================================
+// Details: MI common code implementation class. Logs application fn trace/message/
+// error messages to a file. Used as part of the CMICmnLog Logger
+// system. When instantiated *this object is register with the Logger
+// which the Logger when given data to write to registered medium comes
+// *this medium.
+// Singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 30/01/2014.
+// Changes: None.
+//--
+class CMICmnLogMediumFile
+: public CMICmnBase
+, public CMICmnLog::IMedium
+{
+// Statics:
+public:
+ static CMICmnLogMediumFile & Instance( void );
+
+// Methods:
+public:
+ bool SetHeaderTxt( const CMIUtilString & vText );
+ bool SetVerbosity( const MIuint veType );
+ MIuint GetVerbosity( void ) const;
+ const CMIUtilString & GetFileName( void ) const;
+ const CMIUtilString & GetFileNamePath( void ) const;
+ bool IsOk( void ) const;
+ bool IsFileExist( void ) const;
+ const CMIUtilString & GetLineReturn( void ) const;
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnLogMediumFile( void );
+ // From CMICmnLog::IMedium
+ virtual bool Initialize( void );
+ virtual const CMIUtilString & GetName( void ) const;
+ virtual bool Write( const CMIUtilString & vData, const CMICmnLog::ELogVerbosity veType );
+ virtual const CMIUtilString & GetError( void ) const;
+ virtual bool Shutdown( void );
+
+// Methods:
+private:
+ /* ctor */ CMICmnLogMediumFile( void );
+ /* ctor */ CMICmnLogMediumFile( const CMICmnLogMediumFile & );
+ void operator=( const CMICmnLogMediumFile & );
+
+ bool FileWriteEnglish( const CMIUtilString & vData );
+ bool FileFormFileNamePath( void );
+ CMIUtilString MassagedData( const CMIUtilString & vData, const CMICmnLog::ELogVerbosity veType );
+ bool FileWriteHeader( void );
+ MIchar ConvertLogVerbosityTypeToId( const CMICmnLog::ELogVerbosity veType ) const;
+ CMIUtilString ConvertCr( const CMIUtilString & vData ) const;
+
+// Attributes:
+private:
+ const CMIUtilString m_constThisMediumName;
+ const CMIUtilString m_constMediumFileName;
+ //
+ CMIUtilString m_fileNamePath;
+ MIuint m_eVerbosityType;
+ CMIUtilString m_strDate;
+ CMIUtilString m_fileHeaderTxt;
+ CMIUtilFileStd m_file;
+ CMIUtilDateTimeStd m_dateTime;
+};
diff --git a/tools/lldb-mi/MICmnMIOutOfBandRecord.cpp b/tools/lldb-mi/MICmnMIOutOfBandRecord.cpp
new file mode 100644
index 000000000000..c3826f01ae85
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIOutOfBandRecord.cpp
@@ -0,0 +1,161 @@
+//===-- MICmnMIOutOfBandRecord.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIOutOfBandRecord.h
+//
+// Overview: CMICmnMIOutOfBandRecord implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnMIOutOfBandRecord.h"
+#include "MICmnResources.h"
+
+// Instantiations:
+CMICmnMIOutOfBandRecord::MapOutOfBandToOutOfBandText_t ms_MapOutOfBandToOutOfBandText =
+{
+ { CMICmnMIOutOfBandRecord::eOutOfBand_Running, "running" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, "stopped" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_BreakPointCreated, "breakpoint-created" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_BreakPointModified, "breakpoint-modified" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_Thread, "" }, // "" Meant to be empty
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupAdded, "thread-group-added" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupExited, "thread-group-exited" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupRemoved, "thread-group-removed" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, "thread-group-started" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadCreated, "thread-created" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadExited, "thread-exited" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, "thread-selected" }
+};
+CMICmnMIOutOfBandRecord::MapOutOfBandToOutOfBandText_t ms_constMapAsyncRecordTextToToken =
+{
+ { CMICmnMIOutOfBandRecord::eOutOfBand_Running, "*" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, "*" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_BreakPointCreated, "=" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_BreakPointModified, "=" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_Thread, "@" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupAdded, "=" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupExited, "=" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupRemoved, "=" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, "=" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadCreated, "=" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadExited, "=" },
+ { CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, "=" }
+};
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIOutOfBandRecord constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIOutOfBandRecord::CMICmnMIOutOfBandRecord( void )
+: m_strAsyncRecord( MIRSRC( IDS_CMD_ERR_EVENT_HANDLED_BUT_NO_ACTION ) )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIOutOfBandRecord constructor.
+// Type: Method.
+// Args: veType - (R) A MI Out-of-Bound enumeration.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIOutOfBandRecord::CMICmnMIOutOfBandRecord( const OutOfBand_e veType )
+: m_eResultAsyncRecordClass( veType )
+, m_strAsyncRecord( MIRSRC( IDS_CMD_ERR_EVENT_HANDLED_BUT_NO_ACTION ) )
+{
+ BuildAsyncRecord();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIOutOfBandRecord constructor.
+// Type: Method.
+// Args: veType - (R) A MI Out-of-Bound enumeration.
+// vMIResult - (R) A MI result object.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIOutOfBandRecord::CMICmnMIOutOfBandRecord( const OutOfBand_e veType, const CMICmnMIValueResult & vValue )
+: m_eResultAsyncRecordClass( veType )
+, m_strAsyncRecord( MIRSRC( IDS_CMD_ERR_EVENT_HANDLED_BUT_NO_ACTION ) )
+, m_partResult( vValue )
+{
+ BuildAsyncRecord();
+ Add( m_partResult );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIOutOfBandRecord destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIOutOfBandRecord::~CMICmnMIOutOfBandRecord( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Return the MI Out-of-band record as a string. The string is a direct result of
+// work done on *this Out-of-band record so if not enough data is added then it is
+// possible to return a malformed Out-of-band record. If nothing has been set or
+// added to *this MI Out-of-band record object then text "<Invalid>" will be returned.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - MI output text.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnMIOutOfBandRecord::GetString( void ) const
+{
+ return m_strAsyncRecord;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Build the Out-of-band record's mandatory data part. The part up to the first
+// (additional) result i.e. async-record ==> "*" type.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIOutOfBandRecord::BuildAsyncRecord( void )
+{
+ const MIchar * pFormat = "%s%s";
+ const CMIUtilString & rStrAsyncRecord( ms_MapOutOfBandToOutOfBandText[ m_eResultAsyncRecordClass ] );
+ const CMIUtilString & rStrToken( ms_constMapAsyncRecordTextToToken[ m_eResultAsyncRecordClass ] );
+ m_strAsyncRecord = CMIUtilString::Format( pFormat, rStrToken.c_str(), rStrAsyncRecord.c_str() );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add to *this Out-of-band record additional information.
+// Type: Method.
+// Args: vMIValue - (R) A MI value derived object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIOutOfBandRecord::Add( const CMICmnMIValue & vMIValue )
+{
+ m_strAsyncRecord += ",";
+ m_strAsyncRecord += vMIValue.GetString();
+
+ return MIstatus::success;
+}
+
diff --git a/tools/lldb-mi/MICmnMIOutOfBandRecord.h b/tools/lldb-mi/MICmnMIOutOfBandRecord.h
new file mode 100644
index 000000000000..1a8f7a2e2009
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIOutOfBandRecord.h
@@ -0,0 +1,110 @@
+//===-- MICmnMIOutOfBandRecord.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIOutOfBandRecord.h
+//
+// Overview: CMICmnMIOutOfBandRecord interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <map>
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MIUtilString.h"
+#include "MICmnMIValueResult.h"
+
+//++ ============================================================================
+// Details: MI common code MI Out-of-band (Async) Record class. A class that encapsulates
+// MI result record data and the forming/format of data added to it.
+// Out-of-band records are used to notify the GDB/MI client of additional
+// changes that have occurred. Those changes can either be a consequence
+// of GDB/MI (e.g., a breakpoint modified) or a result of target activity
+// (e.g., target stopped).
+// The syntax is as follows:
+// "*" type ( "," result )*
+// type ==> running | stopped
+//
+// The Out-of-band record can be retrieve at any time *this object is
+// instantiated so unless work is done on *this Out-of-band record then it is
+// possible to return a malformed Out-of-band record. If nothing has been set
+// or added to *this MI Out-of-band record object then text "<Invalid>" will
+// be returned.
+//
+// More information see:
+// http://ftp.gnu.org/old-gnu/Manuals/gdb-5.1.1/html_chapter/gdb_22.html//
+// Gotchas: None.
+// Authors: Illya Rudkin 24/02/2014.
+// Changes: None.
+//--
+class CMICmnMIOutOfBandRecord : public CMICmnBase
+{
+// Enumerations:
+public:
+ //++
+ // Details: Enumeration of the type of Out-of-band for *this Out-of-band record
+ //--
+ enum OutOfBand_e
+ {
+ eOutOfBand_Running = 0,
+ eOutOfBand_Stopped,
+ eOutOfBand_BreakPointCreated,
+ eOutOfBand_BreakPointModified,
+ eOutOfBand_Thread,
+ eOutOfBand_ThreadGroupAdded,
+ eOutOfBand_ThreadGroupExited,
+ eOutOfBand_ThreadGroupRemoved,
+ eOutOfBand_ThreadGroupStarted,
+ eOutOfBand_ThreadCreated,
+ eOutOfBand_ThreadExited,
+ eOutOfBand_ThreadSelected,
+ eOutOfBand_count // Always the last one
+ };
+
+// Typedefs:
+public:
+ typedef std::map< OutOfBand_e, CMIUtilString > MapOutOfBandToOutOfBandText_t;
+ typedef std::map< OutOfBand_e, CMIUtilString > MapOutOfBandToToken_t;
+
+// Methods:
+public:
+ /* ctor */ CMICmnMIOutOfBandRecord( void );
+ /* ctor */ CMICmnMIOutOfBandRecord( const OutOfBand_e veType );
+ /* ctor */ CMICmnMIOutOfBandRecord( const OutOfBand_e veType, const CMICmnMIValueResult & vValue );
+ //
+ const CMIUtilString & GetString( void ) const;
+ bool Add( const CMICmnMIValue & vMIValue );
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnMIOutOfBandRecord( void );
+
+// Methods:
+private:
+ bool BuildAsyncRecord( void );
+
+// Attributes:
+private:
+ static MapOutOfBandToOutOfBandText_t ms_constMapOutOfBandToAsyncRecordText;
+ static MapOutOfBandToToken_t ms_constMapOutOfBandTextToToken;
+ //
+ OutOfBand_e m_eResultAsyncRecordClass;
+ CMIUtilString m_strAsyncRecord; // Holds the text version of the result record to date
+ CMICmnMIValueResult m_partResult;
+};
diff --git a/tools/lldb-mi/MICmnMIResultRecord.cpp b/tools/lldb-mi/MICmnMIResultRecord.cpp
new file mode 100644
index 000000000000..195167981d8c
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIResultRecord.cpp
@@ -0,0 +1,142 @@
+//===-- Platform.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIResultRecord.h
+//
+// Overview: CMICmnMIResultRecord implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnMIResultRecord.h"
+#include "MICmnResources.h"
+
+// Instantiations:
+CMICmnMIResultRecord::MapResultClassToResultClassText_t ms_MapResultClassToResultClassText =
+{
+ { CMICmnMIResultRecord::eResultClass_Done, "done" },
+ { CMICmnMIResultRecord::eResultClass_Running, "running" },
+ { CMICmnMIResultRecord::eResultClass_Connected, "connected" },
+ { CMICmnMIResultRecord::eResultClass_Error, "error" },
+ { CMICmnMIResultRecord::eResultClass_Exit, "exit" }
+};
+const CMIUtilString CMICmnMIResultRecord::ms_constStrResultRecordHat( "^");
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIResultRecord constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIResultRecord::CMICmnMIResultRecord( void )
+: m_strResultRecord( MIRSRC( IDS_CMD_ERR_CMD_RUN_BUT_NO_ACTION ) )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIResultRecord constructor.
+// Type: Method.
+// Args: vrToken - (R) The command's transaction ID or token.
+// veType - (R) A MI result class enumeration.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIResultRecord::CMICmnMIResultRecord( const CMIUtilString & vrToken, const ResultClass_e veType )
+: m_strResultRecordToken( vrToken )
+, m_eResultRecordResultClass( veType )
+, m_strResultRecord( MIRSRC( IDS_CMD_ERR_CMD_RUN_BUT_NO_ACTION ) )
+{
+ BuildResultRecord();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIResultRecord constructor.
+// Type: Method.
+// Args: vrToken - (R) The command's transaction ID or token.
+// veType - (R) A MI result class enumeration.
+// vMIResult - (R) A MI result object.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIResultRecord::CMICmnMIResultRecord( const CMIUtilString & vrToken, const ResultClass_e veType, const CMICmnMIValueResult & vValue )
+: m_strResultRecordToken( vrToken )
+, m_eResultRecordResultClass( veType )
+, m_strResultRecord( MIRSRC( IDS_CMD_ERR_CMD_RUN_BUT_NO_ACTION ) )
+, m_partResult( vValue )
+{
+ BuildResultRecord();
+ Add( m_partResult );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIResultRecord destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIResultRecord::~CMICmnMIResultRecord( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Return the MI result record as a string. The string is a direct result of
+// work done on *this result record so if not enough data is added then it is
+// possible to return a malformed result record. If nothing has been set or
+// added to *this MI result record object then text "<Invalid>" will be returned.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - MI output text.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnMIResultRecord::GetString( void ) const
+{
+ return m_strResultRecord;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Build the result record's mandatory data part. The part up to the first
+// (additional) result i.e. result-record ==> [ token ] "^" result-class.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIResultRecord::BuildResultRecord( void )
+{
+ const MIchar * pFormat = "%s%s%s";
+ const CMIUtilString & rStrResultRecord( ms_MapResultClassToResultClassText[ m_eResultRecordResultClass ] );
+ m_strResultRecord = CMIUtilString::Format( pFormat, m_strResultRecordToken.c_str(), ms_constStrResultRecordHat.c_str(), rStrResultRecord.c_str() );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add to *this result record additional information.
+// Type: Method.
+// Args: vMIValue - (R) A MI value derived object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIResultRecord::Add( const CMICmnMIValue & vMIValue )
+{
+ m_strResultRecord += ",";
+ m_strResultRecord += vMIValue.GetString();
+
+ return MIstatus::success;
+}
diff --git a/tools/lldb-mi/MICmnMIResultRecord.h b/tools/lldb-mi/MICmnMIResultRecord.h
new file mode 100644
index 000000000000..c76587d606c8
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIResultRecord.h
@@ -0,0 +1,106 @@
+//===-- MICmnMIResultRecord.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIResultRecord.h
+//
+// Overview: CMICmnMIResultRecord interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <map>
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MIUtilString.h"
+#include "MICmnMIValueResult.h"
+
+//++ ============================================================================
+// Details: MI common code MI Result Record class. A class that encapsulates
+// MI result record data and the forming/format of data added to it.
+// The syntax is as follows:
+// result-record ==> [ token ] "^" result-class ( "," result )* nl
+// token = any sequence of digits
+// * = 0 to many
+// nl = CR | CR_LF
+// result-class ==> "done" | "running" | "connected" | "error" | "exit"
+// result ==> variable "=" value
+// value ==> const | tuple | list
+// const ==> c-string (7 bit iso c string content) i.e. "all" inc quotes
+// tuple ==> "{}" | "{" result ( "," result )* "}"
+// list ==> "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]"
+//
+// The result record can be retrieve at any time *this object is
+// instantiated so unless work is done on *this result record then it is
+// possible to return a malformed result record. If nothing has been set
+// or added to *this MI result record object then text "<Invalid>" will
+// be returned.
+// More information see:
+// http://ftp.gnu.org/old-gnu/Manuals/gdb-5.1.1/html_chapter/gdb_22.html
+// Gotchas: None.
+// Authors: Illya Rudkin 24/02/2014.
+// Changes: None.
+//--
+class CMICmnMIResultRecord : public CMICmnBase
+{
+// Enumerations:
+public:
+ //++
+ // Details: Enumeration of the result class for *this result record
+ //--
+ enum ResultClass_e
+ {
+ eResultClass_Done = 0,
+ eResultClass_Running,
+ eResultClass_Connected,
+ eResultClass_Error,
+ eResultClass_Exit,
+ eResultClass_count // Always the last one
+ };
+
+// Typedefs:
+public:
+ typedef std::map< ResultClass_e, CMIUtilString > MapResultClassToResultClassText_t;
+
+// Methods:
+public:
+ /* ctor */ CMICmnMIResultRecord( void );
+ /* ctor */ CMICmnMIResultRecord( const CMIUtilString & vrToken, const ResultClass_e veType );
+ /* ctor */ CMICmnMIResultRecord( const CMIUtilString & vrToken, const ResultClass_e veType, const CMICmnMIValueResult & vValue );
+ //
+ const CMIUtilString & GetString( void ) const;
+ bool Add( const CMICmnMIValue & vMIValue );
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnMIResultRecord( void );
+
+// Methods:
+private:
+ bool BuildResultRecord( void );
+
+// Attributes:
+private:
+ static const CMIUtilString ms_constStrResultRecordHat;
+ static MapResultClassToResultClassText_t ms_constMapResultClassToResultClassText;
+ //
+ CMIUtilString m_strResultRecordToken;
+ ResultClass_e m_eResultRecordResultClass;
+ CMIUtilString m_strResultRecord; // Holds the text version of the result record to date
+ CMICmnMIValueResult m_partResult;
+};
diff --git a/tools/lldb-mi/MICmnMIValue.cpp b/tools/lldb-mi/MICmnMIValue.cpp
new file mode 100644
index 000000000000..f9fb08bf642d
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIValue.cpp
@@ -0,0 +1,64 @@
+//===-- Platform.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIValue.h
+//
+// Overview: CMICmnMIValue implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnMIValue.h"
+#include "MICmnResources.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValue constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValue::CMICmnMIValue( void )
+: m_strValue( MIRSRC( IDS_WORD_INVALIDBRKTS ) )
+, m_bJustConstructed( true )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValue destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValue::~CMICmnMIValue( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Return the MI value as a string. The string is a direct result of
+// work done on *this value so if not enough data is added then it is
+// possible to return a malformed value. If nothing has been set or
+// added to *this MI value object then text "<Invalid>" will be returned.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - MI output text.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnMIValue::GetString( void ) const
+{
+ return m_strValue;
+}
+
diff --git a/tools/lldb-mi/MICmnMIValue.h b/tools/lldb-mi/MICmnMIValue.h
new file mode 100644
index 000000000000..4cf03122cc28
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIValue.h
@@ -0,0 +1,64 @@
+//===-- MICmnMIValue.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIValue.h
+//
+// Overview: CMICmnMIValue interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmnBase.h"
+
+//++ ============================================================================
+// Details: MI common code MI Result class. Part of the CMICmnMIValueRecord
+// set of objects.
+// The syntax is as follows:
+// result-record ==> [ token ] "^" result-class ( "," result )* nl
+// token = any sequence of digits
+// * = 0 to many
+// nl = CR | CR_LF
+// result-class ==> "done" | "running" | "connected" | "error" | "exit"
+// result ==> variable "=" value
+// value ==> const | tuple | list
+// const ==> c-string (7 bit iso c string content)
+// tuple ==> "{}" | "{" result ( "," result )* "}"
+// list ==> "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]"
+// More information see:
+// http://ftp.gnu.org/old-gnu/Manuals/gdb-5.1.1/html_chapter/gdb_22.html
+// Gotchas: None.
+// Authors: Illya Rudkin 24/02/2014.
+// Changes: None.
+//--
+class CMICmnMIValue : public CMICmnBase
+{
+// Methods:
+public:
+ /* ctor */ CMICmnMIValue( void );
+ //
+ const CMIUtilString & GetString( void ) const;
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnMIValue( void );
+
+// Attributes:
+protected:
+ CMIUtilString m_strValue;
+ bool m_bJustConstructed; // True = *this just constructed with no value, false = *this has had value added to it
+};
diff --git a/tools/lldb-mi/MICmnMIValueConst.cpp b/tools/lldb-mi/MICmnMIValueConst.cpp
new file mode 100644
index 000000000000..afac8df07d78
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIValueConst.cpp
@@ -0,0 +1,98 @@
+//===-- Platform.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIValueConst.h
+//
+// Overview: CMICmnMIValueConst implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnMIValueConst.h"
+
+// Instantiations:
+const CMIUtilString CMICmnMIValueConst::ms_constStrDblQuote( "\"" );
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueConst constructor.
+// Type: Method.
+// Args: vString - (R) MI Const c-string value.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueConst::CMICmnMIValueConst( const CMIUtilString & vString )
+: m_strPartConst( vString )
+, m_bNoQuotes( false )
+{
+ BuildConst();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueConst constructor.
+// Type: Method.
+// Args: vString - (R) MI Const c-string value.
+// vbNoQuotes - (R) True = return string not surrounded with quotes, false = use quotes.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueConst::CMICmnMIValueConst( const CMIUtilString & vString, const bool vbNoQuotes )
+: m_strPartConst( vString )
+, m_bNoQuotes( vbNoQuotes )
+{
+ BuildConst();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueConst destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueConst::~CMICmnMIValueConst( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Build the Value Const data.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueConst::BuildConst( void )
+{
+ if( m_strPartConst.length() != 0 )
+ {
+ const CMIUtilString strValue( m_strPartConst.StripCREndOfLine() );
+ if( m_bNoQuotes )
+ {
+ m_strValue = strValue;
+ }
+ else
+ {
+ const MIchar * pFormat = "%s%s%s";
+ m_strValue = CMIUtilString::Format( pFormat, ms_constStrDblQuote.c_str(), strValue.c_str(), ms_constStrDblQuote.c_str() );
+ }
+ }
+ else
+ {
+ const MIchar * pFormat = "%s%s";
+ m_strValue = CMIUtilString::Format( pFormat, ms_constStrDblQuote.c_str(), ms_constStrDblQuote.c_str() );
+ }
+
+ return MIstatus::success;
+} \ No newline at end of file
diff --git a/tools/lldb-mi/MICmnMIValueConst.h b/tools/lldb-mi/MICmnMIValueConst.h
new file mode 100644
index 000000000000..ddb440d7c6ec
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIValueConst.h
@@ -0,0 +1,72 @@
+//===-- MICmnMIValueConst.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIValueConst.h
+//
+// Overview: CMICmnMIValueConst interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmnMIValue.h"
+
+//++ ============================================================================
+// Details: MI common code MI Result class. Part of the CMICmnMIValueConstRecord
+// set of objects.
+// The syntax is as follows:
+// result-record ==> [ token ] "^" result-class ( "," result )* nl
+// token = any sequence of digits
+// * = 0 to many
+// nl = CR | CR_LF
+// result-class ==> "done" | "running" | "connected" | "error" | "exit"
+// result ==> variable "=" value
+// value ==> const | tuple | list
+// const ==> c-string (7 bit iso c string content)
+// tuple ==> "{}" | "{" result ( "," result )* "}"
+// list ==> "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]"
+// More information see:
+// http://ftp.gnu.org/old-gnu/Manuals/gdb-5.1.1/html_chapter/gdb_22.html
+//
+// The text formed in *this Result class is stripped of any '\n' characters.
+//
+// Gotchas: None.
+// Authors: Illya Rudkin 24/02/2014.
+// Changes: None.
+//--
+class CMICmnMIValueConst : public CMICmnMIValue
+{
+// Methods:
+public:
+ /* ctor */ CMICmnMIValueConst( const CMIUtilString & vString );
+ /* ctor */ CMICmnMIValueConst( const CMIUtilString & vString, const bool vbNoQuotes );
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnMIValueConst( void );
+
+// Methods:
+private:
+ bool BuildConst( void );
+
+// Attributes:
+private:
+ static const CMIUtilString ms_constStrDblQuote;
+ //
+ CMIUtilString m_strPartConst;
+ bool m_bNoQuotes; // True = return string not surrounded with quotes, false = use quotes
+};
diff --git a/tools/lldb-mi/MICmnMIValueList.cpp b/tools/lldb-mi/MICmnMIValueList.cpp
new file mode 100644
index 000000000000..97a08cd29f09
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIValueList.cpp
@@ -0,0 +1,203 @@
+//===-- Platform.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIValueList.h
+//
+// Overview: CMICmnMIValueList implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnMIValueList.h"
+#include "MICmnResources.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueList constructor.
+// Type: Method.
+// Args: vbValueTypeList - (R) True = yes value type list, false = result type list.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueList::CMICmnMIValueList( const bool vbValueTypeList )
+{
+ m_strValue = "[]";
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueList constructor.
+// Construct a results only list.
+// return MIstatus::failure.
+// Type: Method.
+// Args: vResult - (R) MI result object.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueList::CMICmnMIValueList( const CMICmnMIValueResult & vResult )
+{
+ m_strValue = vResult.GetString();
+ BuildList();
+ m_bJustConstructed = false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueList constructor.
+// Construct a value only list.
+// Type: Method.
+// Args: vValue - (R) MI value object.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueList::CMICmnMIValueList( const CMICmnMIValue & vValue )
+{
+ m_strValue = vValue.GetString();
+ BuildList();
+ m_bJustConstructed = false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueList destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueList::~CMICmnMIValueList( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Build the result value's mandatory data part, one tuple
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueList::BuildList( void )
+{
+ const MIchar * pFormat = "[%s]";
+ m_strValue = CMIUtilString::Format( pFormat, m_strValue.c_str() );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add another MI result object to the value list's of list is results.
+// Only result obejcts can be added to a list of result otherwise this function
+// will return MIstatus::failure.
+// Type: Method.
+// Args: vResult - (R) The MI result object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueList::Add( const CMICmnMIValueResult & vResult )
+{
+ return BuildList( vResult );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add another MI value object to the value list's of list is values.
+// Only values objects can be added to a list of values otherwise this function
+// will return MIstatus::failure.
+// Type: Method.
+// Args: vValue - (R) The MI value object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueList::Add( const CMICmnMIValue & vValue )
+{
+ return BuildList( vValue );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add another MI result object to the value list's of list is results.
+// Only result obejcts can be added to a list of result otherwise this function
+// will return MIstatus::failure.
+// Type: Method.
+// Args: vResult - (R) The MI result object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueList::BuildList( const CMICmnMIValueResult & vResult )
+{
+ // Clear out the default "<Invalid>" text
+ if( m_bJustConstructed )
+ {
+ m_bJustConstructed = false;
+ m_strValue = vResult.GetString();
+ return BuildList();
+ }
+
+ const CMIUtilString data( ExtractContentNoBrackets() );
+ const MIchar * pFormat = "[%s,%s]";
+ m_strValue = CMIUtilString::Format( pFormat, data.c_str(), vResult.GetString().c_str() );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add another MI value object to the value list's of list is values.
+// Only values objects can be added to a list of values otherwise this function
+// will return MIstatus::failure.
+// Type: Method.
+// Args: vValue - (R) The MI value object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueList::BuildList( const CMICmnMIValue & vValue )
+{
+ // Clear out the default "<Invalid>" text
+ if( m_bJustConstructed )
+ {
+ m_bJustConstructed = false;
+ m_strValue = vValue.GetString();
+ return BuildList();
+ }
+
+ const MIchar * pFormat = "[%s,%s]";
+ m_strValue = m_strValue.FindAndReplace( "[", "" );
+ m_strValue = m_strValue.FindAndReplace( "]", "" );
+ m_strValue = CMIUtilString::Format( pFormat, m_strValue.c_str(), vValue.GetString().c_str() );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the contents of *this value object but without the outer most
+// brackets.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Data within the object.
+// Throws: None.
+//--
+CMIUtilString CMICmnMIValueList::ExtractContentNoBrackets( void ) const
+{
+ CMIUtilString data( m_strValue );
+
+ if( data[ 0 ] == '[' )
+ {
+ data = data.substr( 1, data.length() - 1 );
+ }
+ if( data[ data.size() - 1 ] == ']' )
+ {
+ data = data.substr( 0, data.length() - 1 );
+ }
+
+ return data;
+}
diff --git a/tools/lldb-mi/MICmnMIValueList.h b/tools/lldb-mi/MICmnMIValueList.h
new file mode 100644
index 000000000000..cd1a98f7705f
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIValueList.h
@@ -0,0 +1,70 @@
+//===-- MICmnMIValueList.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIValueList.h
+//
+// Overview: CMICmnMIValueList interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmnMIValue.h"
+#include "MICmnMIValueResult.h"
+
+//++ ============================================================================
+// Details: MI common code MI Result class. Part of the CMICmnMIValueListRecord
+// set of objects.
+// The syntax is as follows:
+// result-record ==> [ token ] "^" result-class ( "," result )* nl
+// token = any sequence of digits
+// * = 0 to many
+// nl = CR | CR_LF
+// result-class ==> "done" | "running" | "connected" | "error" | "exit"
+// result ==> variable "=" value
+// value ==> const | tuple | list
+// const ==> c-string (7 bit iso c string content)
+// tuple ==> "{}" | "{" result ( "," result )* "}"
+// list ==> "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]"
+// More information see:
+// http://ftp.gnu.org/old-gnu/Manuals/gdb-5.1.1/html_chapter/gdb_22.html
+// Gotchas: None.
+// Authors: Illya Rudkin 24/02/2014.
+// Changes: None.
+//--
+class CMICmnMIValueList : public CMICmnMIValue
+{
+// Methods:
+public:
+ /* ctor */ CMICmnMIValueList( const bool vbValueTypeList );
+ /* ctor */ CMICmnMIValueList( const CMICmnMIValueResult & vResult );
+ /* ctor */ CMICmnMIValueList( const CMICmnMIValue & vValue );
+ //
+ bool Add( const CMICmnMIValueResult & vResult );
+ bool Add( const CMICmnMIValue & vValue );
+ CMIUtilString ExtractContentNoBrackets( void ) const;
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnMIValueList( void );
+
+// Methods:
+private:
+ bool BuildList( void );
+ bool BuildList( const CMICmnMIValueResult & vResult );
+ bool BuildList( const CMICmnMIValue & vResult );
+};
diff --git a/tools/lldb-mi/MICmnMIValueResult.cpp b/tools/lldb-mi/MICmnMIValueResult.cpp
new file mode 100644
index 000000000000..e5cc9ce2bb1c
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIValueResult.cpp
@@ -0,0 +1,141 @@
+//===-- Platform.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIResult.h
+//
+// Overview: CMICmnMIValueResult implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnMIValueResult.h"
+#include "MICmnResources.h"
+
+// Instantiations:
+const CMIUtilString CMICmnMIValueResult::ms_constStrEqual( "=" );
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueResult constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueResult::CMICmnMIValueResult( void )
+: m_bEmptyConstruction( true )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueResult constructor.
+// Type: Method.
+// Args: vrVariable - (R) MI value's name.
+// vrValue - (R) The MI value.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueResult::CMICmnMIValueResult( const CMIUtilString & vrVariable, const CMICmnMIValue & vrValue )
+: m_strPartVariable( vrVariable )
+, m_partMIValue( vrValue )
+, m_bEmptyConstruction( false )
+, m_bUseSpacing( false )
+{
+ BuildResult();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueResult constructor.
+// Type: Method.
+// Args: vrVariable - (R) MI value's name.
+// vrValue - (R) The MI value.
+// vbUseSpacing - (R) True = put space seperators into the string, false = no spaces used.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueResult::CMICmnMIValueResult( const CMIUtilString & vrVariable, const CMICmnMIValue & vrValue, const bool vbUseSpacing )
+: m_strPartVariable( vrVariable )
+, m_partMIValue( vrValue )
+, m_bEmptyConstruction( false )
+, m_bUseSpacing( vbUseSpacing )
+{
+ BuildResult();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueResult destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueResult::~CMICmnMIValueResult( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Build the MI value result string.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueResult::BuildResult( void )
+{
+ const MIchar * pFormat = m_bUseSpacing ? "%s %s %s" : "%s%s%s";
+ m_strValue = CMIUtilString::Format( pFormat, m_strPartVariable.c_str(), ms_constStrEqual.c_str(), m_partMIValue.GetString().c_str() );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Build the MI value result string.
+// Type: Method.
+// Args: vrVariable - (R) MI value's name.
+// vrValue - (R) The MI value.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueResult::BuildResult( const CMIUtilString & vVariable, const CMICmnMIValue & vValue )
+{
+ const MIchar * pFormat = m_bUseSpacing ? "%s, %s %s %s" : "%s,%s%s%s";
+ m_strValue = CMIUtilString::Format( pFormat, m_strValue.c_str(), vVariable.c_str(), ms_constStrEqual.c_str(), vValue.GetString().c_str() );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Append another MI value object to *this MI value result.
+// Type: Method.
+// Args: vrVariable - (R) MI value's name.
+// vrValue - (R) The MI value.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueResult::Add( const CMIUtilString & vrVariable, const CMICmnMIValue & vrValue )
+{
+ if( !m_bEmptyConstruction )
+ return BuildResult( vrVariable, vrValue );
+ else
+ {
+ m_bEmptyConstruction = false;
+ m_strPartVariable = vrVariable;
+ m_partMIValue = vrValue;
+ return BuildResult();
+ }
+}
+
diff --git a/tools/lldb-mi/MICmnMIValueResult.h b/tools/lldb-mi/MICmnMIValueResult.h
new file mode 100644
index 000000000000..a9a2a930c93e
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIValueResult.h
@@ -0,0 +1,75 @@
+//===-- MICmnMIResult.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIResult.h
+//
+// Overview: CMICmnMIValueResult interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmnMIValue.h"
+
+//++ ============================================================================
+// Details: MI common code MI Result class. Part of the CMICmnMIValueResultRecord
+// set of objects.
+// The syntax is as follows:
+// result-record ==> [ token ] "^" result-class ( "," result )* nl
+// token = any sequence of digits
+// * = 0 to many
+// nl = CR | CR_LF
+// result-class ==> "done" | "running" | "connected" | "error" | "exit"
+// result ==> variable "=" value
+// value ==> const | tuple | list
+// const ==> c-string (7 bit iso c string content)
+// tuple ==> "{}" | "{" result ( "," result )* "}"
+// list ==> "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]"
+// More information see:
+// http://ftp.gnu.org/old-gnu/Manuals/gdb-5.1.1/html_chapter/gdb_22.html
+// Gotchas: None.
+// Authors: Illya Rudkin 24/02/2014.
+// Changes: None.
+//--
+class CMICmnMIValueResult : public CMICmnMIValue
+{
+// Methods:
+public:
+ /* ctor */ CMICmnMIValueResult( void );
+ /* ctor */ CMICmnMIValueResult( const CMIUtilString & vVariable, const CMICmnMIValue & vValue );
+ /* ctor */ CMICmnMIValueResult( const CMIUtilString & vVariable, const CMICmnMIValue & vValue, const bool vbUseSpacing );
+ //
+ bool Add( const CMIUtilString & vVariable, const CMICmnMIValue & vValue );
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnMIValueResult( void );
+
+// Methods:
+private:
+ bool BuildResult( void );
+ bool BuildResult( const CMIUtilString & vVariable, const CMICmnMIValue & vValue );
+
+// Attributes:
+private:
+ static const CMIUtilString ms_constStrEqual;
+ //
+ CMIUtilString m_strPartVariable;
+ CMICmnMIValue m_partMIValue;
+ bool m_bEmptyConstruction; // True = *this object used constructor with no parameters, false = constructor with parameters
+ bool m_bUseSpacing; // True = put space seperators into the string, false = no spaces used
+};
diff --git a/tools/lldb-mi/MICmnMIValueTuple.cpp b/tools/lldb-mi/MICmnMIValueTuple.cpp
new file mode 100644
index 000000000000..2f1349e79795
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIValueTuple.cpp
@@ -0,0 +1,227 @@
+//===-- Platform.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIValueTuple.h
+//
+// Overview: CMICmnMIValueTuple implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnMIValueTuple.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueTuple constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueTuple::CMICmnMIValueTuple( void )
+: m_bSpaceAfterComma( false )
+{
+ m_strValue = "{}";
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueTuple constructor.
+// Type: Method.
+// Args: vResult - (R) MI result object.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueTuple::CMICmnMIValueTuple( const CMICmnMIValueResult & vResult )
+: m_bSpaceAfterComma( false )
+{
+ m_strValue = vResult.GetString();
+ BuildTuple();
+ m_bJustConstructed = false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueTuple constructor.
+// Type: Method.
+// Args: vResult - (R) MI result object.
+// vbUseSpacing - (R) True = put space seperators into the string, false = no spaces used.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueTuple::CMICmnMIValueTuple( const CMICmnMIValueResult & vResult, const bool vbUseSpacing )
+: m_bSpaceAfterComma( vbUseSpacing )
+{
+ m_strValue = vResult.GetString();
+ BuildTuple();
+ m_bJustConstructed = false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnMIValueTuple destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnMIValueTuple::~CMICmnMIValueTuple( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Build the result value's mandatory data part, one tuple
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueTuple::BuildTuple( void )
+{
+ const MIchar * pFormat = "{%s}";
+ m_strValue = CMIUtilString::Format( pFormat, m_strValue.c_str() );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add another MI result object to the value's list of tuples.
+// Type: Method.
+// Args: vResult - (R) The MI result object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueTuple::BuildTuple( const CMICmnMIValueResult & vResult )
+{
+ // Clear out the default "<Invalid>" text
+ if( m_bJustConstructed )
+ {
+ m_bJustConstructed = false;
+ m_strValue = vResult.GetString();
+ return BuildTuple();
+ }
+
+ if( m_strValue[ 0 ] == '{' )
+ {
+ m_strValue = m_strValue.substr( 1, m_strValue.size() - 1 );
+ }
+ if( m_strValue[ m_strValue.size() - 1 ] == '}' )
+ {
+ m_strValue = m_strValue.substr( 0, m_strValue.size() - 1 );
+ }
+
+ const MIchar * pFormat = m_bSpaceAfterComma ? "{%s, %s}" : "{%s,%s}";
+ m_strValue = CMIUtilString::Format( pFormat, m_strValue.c_str(), vResult.GetString().c_str() );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add string value to the value's list of tuples.
+// Type: Method.
+// Args: vValue - (R) The string object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueTuple::BuildTuple( const CMIUtilString & vValue )
+{
+ // Clear out the default "<Invalid>" text
+ if( m_bJustConstructed )
+ {
+ m_bJustConstructed = false;
+ m_strValue = vValue;
+ return BuildTuple();
+ }
+
+ const CMIUtilString data( ExtractContentNoBrackets() );
+ const MIchar * pFormat = m_bSpaceAfterComma ? "{%s, %s}" : "{%s,%s}";
+ m_strValue = CMIUtilString::Format( pFormat, data.c_str(), vValue.c_str() );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add another MI value object to the value list's of list is values.
+// Only values objects can be added to a list of values otherwise this function
+// will return MIstatus::failure.
+// Type: Method.
+// Args: vValue - (R) The MI value object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueTuple::Add( const CMICmnMIValueResult & vResult )
+{
+ return BuildTuple( vResult );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add another MI value object to the value list's of list is values.
+// Only values objects can be added to a list of values otherwise this function
+// will return MIstatus::failure.
+// Type: Method.
+// Args: vValue - (R) The MI value object.
+// vbUseSpacing - (R) True = put space seperators into the string, false = no spaces used.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueTuple::Add( const CMICmnMIValueResult & vResult, const bool vbUseSpacing )
+{
+ m_bSpaceAfterComma = vbUseSpacing;
+ return BuildTuple( vResult );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add another MI value object to the value list's of list is values.
+// Only values objects can be added to a list of values otherwise this function
+// will return MIstatus::failure.
+// Type: Method.
+// Args: vValue - (R) The MI value object.
+// vbUseSpacing - (R) True = put space seperators into the string, false = no spaces used.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnMIValueTuple::Add( const CMICmnMIValueConst & vValue, const bool vbUseSpacing )
+{
+ m_bSpaceAfterComma = vbUseSpacing;
+ return BuildTuple( vValue.GetString() );
+}
+
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the contents of *this value object but without the outer most
+// brackets.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Data within the object.
+// Throws: None.
+//--
+CMIUtilString CMICmnMIValueTuple::ExtractContentNoBrackets( void ) const
+{
+ CMIUtilString data( m_strValue );
+
+ if( data[ 0 ] == '{' )
+ {
+ data = data.substr( 1, data.length() - 1 );
+ }
+ if( data[ data.size() - 1 ] == '}' )
+ {
+ data = data.substr( 0, data.length() - 1 );
+ }
+
+ return data;
+}
+
diff --git a/tools/lldb-mi/MICmnMIValueTuple.h b/tools/lldb-mi/MICmnMIValueTuple.h
new file mode 100644
index 000000000000..0399c9d5068f
--- /dev/null
+++ b/tools/lldb-mi/MICmnMIValueTuple.h
@@ -0,0 +1,76 @@
+//===-- MICmnMIValueTuple.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnMIValueTuple.h
+//
+// Overview: CMICmnMIValueTuple interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmnMIValue.h"
+#include "MICmnMIValueResult.h"
+#include "MICmnMIValueConst.h"
+
+//++ ============================================================================
+// Details: MI common code MI Result class. Part of the CMICmnMIValueTupleRecord
+// set of objects.
+// The syntax is as follows:
+// result-record ==> [ token ] "^" result-class ( "," result )* nl
+// token = any sequence of digits
+// * = 0 to many
+// nl = CR | CR_LF
+// result-class ==> "done" | "running" | "connected" | "error" | "exit"
+// result ==> variable "=" value
+// value ==> const | tuple | list
+// const ==> c-string (7 bit iso c string content)
+// tuple ==> "{}" | "{" result ( "," result )* "}"
+// list ==> "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]"
+// More information see:
+// http://ftp.gnu.org/old-gnu/Manuals/gdb-5.1.1/html_chapter/gdb_22.html
+// Gotchas: None.
+// Authors: Illya Rudkin 24/02/2014.
+// Changes: None.
+//--
+class CMICmnMIValueTuple : public CMICmnMIValue
+{
+// Methods:
+public:
+ /* ctor */ CMICmnMIValueTuple( void );
+ /* ctor */ CMICmnMIValueTuple( const CMICmnMIValueResult & vResult );
+ /* ctor */ CMICmnMIValueTuple( const CMICmnMIValueResult & vResult, const bool vbUseSpacing );
+ //
+ bool Add( const CMICmnMIValueResult & vResult );
+ bool Add( const CMICmnMIValueResult & vResult, const bool vbUseSpacing );
+ bool Add( const CMICmnMIValueConst & vValue, const bool vbUseSpacing );
+ CMIUtilString ExtractContentNoBrackets( void ) const;
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnMIValueTuple( void );
+
+// Methods:
+private:
+ bool BuildTuple( void );
+ bool BuildTuple( const CMICmnMIValueResult & vResult );
+ bool BuildTuple( const CMIUtilString & vValue );
+
+// Attributes:
+private:
+ bool m_bSpaceAfterComma; // True = put space seperators into the string, false = no spaces used
+};
diff --git a/tools/lldb-mi/MICmnResources.cpp b/tools/lldb-mi/MICmnResources.cpp
new file mode 100644
index 000000000000..08ac2f0edfe0
--- /dev/null
+++ b/tools/lldb-mi/MICmnResources.cpp
@@ -0,0 +1,409 @@
+//===-- MICmnResources.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnResources.cpp
+//
+// Overview: CMICmnResources implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third party headers
+#include "assert.h"
+
+// In-house headers:
+#include "MICmnResources.h"
+
+// Instantiations:
+const CMICmnResources::SRsrcTextData CMICmnResources::ms_pResourceId2TextData[] =
+{
+ { IDS_PROJNAME, "LLDB Machine Interface Driver (MI) All rights reserved" },
+ { IDS_MI_VERSION_DESCRIPTION_DEBUG, "Version: 1.0.0.9 (Debug)" }, // See version history in MIDriverMain.cpp
+ { IDS_MI_VERSION_DESCRIPTION, "Version: 1.0.0.9" },
+ { IDS_MI_APPNAME_SHORT, "MI" },
+ { IDS_MI_APPNAME_LONG, "Machine Interface Driver" },
+ { IDS_MI_APP_FILEPATHNAME, "Application: %s" },
+ { IDS_MI_APP_ARGS, "Command line args: " },
+ { IDE_MI_VERSION_GDB, "Version: GNU gdb (GDB) 7.4 \n(This is a MI stub on top of LLDB and not GDB)\nAll rights reserved.\n" }, // *** Eclipse needs this exactly!!
+ { IDS_UTIL_FILE_ERR_INVALID_PATHNAME, "File Handler. Invalid file name path" },
+ { IDS_UTIL_FILE_ERR_OPENING_FILE, "File Handler. Error %s opening '%s'" },
+ { IDS_UTIL_FILE_ERR_OPENING_FILE_UNKNOWN, "File Handler. Unknown error opening '%s'" },
+ { IDE_UTIL_FILE_ERR_WRITING_FILE, "File Handler. Error %s writing '%s'" },
+ { IDE_UTIL_FILE_ERR_WRITING_NOTOPEN, "File Handler. File '%s' not open for write" },
+ { IDS_RESOURCES_ERR_STRING_NOT_FOUND, "Resources. String (%d) not found in resources" },
+ { IDS_RESOURCES_ERR_STRING_TABLE_INVALID, "Resources. String resource table is not set up" },
+ { IDS_MI_CLIENT_MSG, "Client message: \"%s\"" },
+ { IDS_LOG_MSG_CREATION_DATE, "Creation date %s time %s%s" },
+ { IDS_LOG_MSG_FILE_LOGGER_PATH, "File logger path: %s%s" },
+ { IDS_LOG_MSG_VERSION, "Version: %s%s" },
+ { IDS_LOG_ERR_FILE_LOGGER_DISABLED, "Log. File logger temporarily disabled due to file error '%s'" },
+ { IDS_LOG_MEDIUM_ERR_INIT, "Log. Medium '%s' initialise failed. %s" },
+ { IDS_LOG_MEDIUM_ERR_WRITE_ANY, "Log. Failed to write log data to any medium." },
+ { IDS_LOG_MEDIUM_ERR_WRITE_MEDIUMFAIL, "Log. One or mediums failed writing log data." },
+ { IDS_MEDIUMFILE_NAME, "File" },
+ { IDS_MEDIUMFILE_ERR_INVALID_PATH, "<Invalid - not set>" },
+ { IDS_MEDIUMFILE_ERR_FILE_HEADER, "<Invalid - header not set>" },
+ { IDS_MEDIUMFILE_NAME_LOG, "File medium. %s" },
+ { IDE_MEDIUMFILE_ERR_GET_FILE_PATHNAME_SYS, "File Medium. Failed to retrieve the system/executable path for the Log file" },
+ { IDE_OS_ERR_UNKNOWN, "Unknown OS error" },
+ { IDE_OS_ERR_RETRIEVING, "Unabled to retrieve OS error message" },
+ { IDS_DRIVERMGR_DRIVER_ERR_INIT, "Driver Manager. Driver '%s' (ID:'%s') initialise failed. %s" },
+ { IDE_MEDIUMSTDERR_NAME, "Stderr" },
+ { IDE_MEDIUMSTDOUT_NAME, "Stdout" },
+ { IDE_MI_APP_EXIT_OK, "Program exited OK" },
+ { IDE_MI_APP_EXIT_WITH_PROBLEM, "Program exited with a problem, see '%s' file" },
+ { IDE_MI_APP_EXIT_WITH_PROBLEM_NO_LOG, "Program exited with a problem, the application's log file '%s' was disabled" },
+ { IDE_MI_APP_DESCRIPTION, "Description:\nThe Machine Interface Driver (MI Driver) is a stand alone executable\nthat either be used via a client i.e. Eclipse or directly from the command\nline. It processes MI commands, actions those commands using the internal\ndebugger then forms MI response formatted text which is returned to the\nclient." },
+ { IDE_MI_APP_INFORMATION, "Information:\nCurrent limitations. The MI Driver currently only handles remote target\ndebugging. Local debugging has not been implemented. The MI Driver has\nbeen designed primarily to be used with Eclipse Juno and a custom plugin.\nThe custom plugin is not necessary to operate the MI Driver." },
+ { IDE_MI_APP_ARG_USAGE, "\nMI driver usage:\n\n\tlldb-mi [--longOption] [-s hortOption] [executeable]\n\n[] = optional argument." },
+ { IDE_MI_APP_ARG_HELP, "-h\n--help\n\tPrints out usage information for the MI debugger. Exit the MI\n\tDriver immediately." },
+ { IDE_MI_APP_ARG_VERSION, "--version\n\tPrints out GNU (gdb) version information. Exit the MI Driver\n\timmediately." },
+ { IDE_MI_APP_ARG_VERSION_LONG, "--versionLong\n\tPrints out MI Driver version information. Exit the MI Driver\n\timmediately." },
+ { IDE_MI_APP_ARG_INTERPRETER, "--interpreter\n\tUse the MI Driver for the debugger (MI mode)(Default is the\n\tLLDB driver). Any LLDB command line options are ignored even\n\tif the MI Driver falls through to the LLDB driver. (Depends\n\ton the build configuration see MICmnConfig.h)\n\tNormally specified by the driver client i.e. Eclipse.\n\tCannot specify an executable with this option, use --executable." },
+ { IDE_MI_APP_ARG_EXECUTEABLE, "--executable\n\tUse the MI Driver in MI mode for the debugging the specified\n\texecutable. Any LLDB command line options are ignored even\n\tif the MI Driver falls through to the LLDB driver. (Depends\n\ton the build configuration see MICmnConfig.h)\n\tNormally specified from the command line." },
+ { IDE_MI_APP_ARG_NO_APP_LOG, "--noLog\n\tUse this argument to tell the MI Driver not to update it's log\n\tfile '%s'." },
+ { IDE_MI_APP_ARG_EXAMPLE, "Example MI command:\n\t3-info-gdb-mi-command gdb-set\n\t3^done,command={exists=\"true\"}" },
+ { IDE_MI_APP_ARG_EXECUTABLE, "executable (NOT IMPLEMENTED)\n\tThe file path to the executable i.e. '\"C:\\My Dev\\foo.exe\"'." },
+ { IDS_STDIN_ERR_INVALID_PROMPT, "Stdin. Invalid prompt description '%s'" },
+ { IDS_STDIN_ERR_THREAD_CREATION_FAILED, "Stdin. Thread creation failed '%s'" },
+ { IDS_STDIN_ERR_THREAD_DELETE, "Stdin. Thread failed to delete '%s'" },
+ { IDS_STDIN_ERR_CHKING_BYTE_AVAILABLE, "Stdin. Peeking on stdin stream '%s'" },
+ { IDS_STDIN_INPUT_CTRL_CHARS, "Stdin. Receive characters not handled as a command: " },
+ { IDS_CMD_QUIT_HELP, "MI Driver Command: quit\n\tExit the MI Driver application." },
+ { IDS_THREADMGR_ERR_THREAD_ID_INVALID, "Thread Mgr. Thread ID '%s' is not valid" },
+ { IDS_THREADMGR_ERR_THREAD_FAIL_CREATE, "Thread Mgr: Failed to create thread '%s'" },
+ { IDS_THREADMGR_ERR_THREAD_ID_NOT_FOUND, "Thread Mgr: Thread with ID '%s' not found" },
+ { IDS_THREADMGR_ERR_THREAD_STILL_ALIVE, "Thread Mgr: The thread(s) are still alive at Thread Mgr shutdown: %s" },
+ { IDS_FALLTHRU_DRIVER_CMD_RECEIVED, "Fall Thru Driver. Received command '%s'. Is was %shandled" },
+ { IDS_CMDFACTORY_ERR_INVALID_CMD_NAME, "Command factory. MI command name '%s' is invalid" },
+ { IDS_CMDFACTORY_ERR_INVALID_CMD_CR8FN, "Command factory. Command creation function invalid for command '%s'. Does function exist? Pointer assigned to it?" },
+ { IDS_CMDFACTORY_ERR_CMD_NOT_REGISTERED, "Command factory. Command '%s' not registered" },
+ { IDS_CMDFACTORY_ERR_CMD_ALREADY_REGED, "Command factory. Command '%s' by that name already registered" },
+ { IDS_CMDMGR_ERR_CMD_FAILED_CREATE, "Command manager. Command creation failed. %s" },
+ { IDS_CMDMGR_ERR_CMD_INVOKER, "Command manager. %s " },
+ { IDS_PROCESS_SIGNAL_RECEIVED, "Process signal. Application received signal '%s' (%d)" },
+ { IDS_MI_INIT_ERR_LOG, "Log. Error occurred during initialisation %s" },
+ { IDS_MI_INIT_ERR_RESOURCES, "Resources. Error occurred during initialisation %s" },
+ { IDS_MI_INIT_ERR_INIT, "Driver. Error occurred during initialisation %s" },
+ { IDS_MI_INIT_ERR_STREAMSTDIN, "Stdin. Error occurred during initialisation %s" },
+ { IDS_MI_INIT_ERR_STREAMSTDIN_OSHANDLER, "Stdin. The OS specific stdin stream handler has not been specified for this OS" },
+ { IDS_MI_INIT_ERR_OS_STDIN_HANDLER, "Stdin handler. Error occurred during initialisation %s" },
+ { IDS_MI_INIT_ERR_STREAMSTDOUT, "Stdout. Error occurred during initialisation %s" },
+ { IDS_MI_INIT_ERR_STREAMSTDERR, "Stderr. Error occurred during initialisation %s" },
+ { IDS_MI_INIT_ERR_FALLTHRUDRIVER, "Fall Through Driver. Error occurred during initialisation %s" },
+ { IDS_MI_INIT_ERR_THREADMGR, "Thread Mgr. Error occurred during initialisation %s" },
+ { IDS_MI_INIT_ERR_CMDINTERPRETER, "Command interpreter. %s" },
+ { IDS_MI_INIT_ERR_CMDMGR, "Command manager. %s" },
+ { IDS_MI_INIT_ERR_CMDFACTORY, "Command factory. %s" },
+ { IDS_MI_INIT_ERR_CMDINVOKER, "Command invoker. %s" },
+ { IDS_MI_INIT_ERR_CMDMONITOR, "Command monitor. %s" },
+ { IDS_MI_INIT_ERR_LLDBDEBUGGER, "LLDB Debugger. %s" },
+ { IDS_MI_INIT_ERR_DRIVERMGR, "Driver manager. %s" },
+ { IDS_MI_INIT_ERR_DRIVER, "Driver. %s" },
+ { IDS_MI_INIT_ERR_OUTOFBANDHANDLER, "Out-of-band handler. %s " },
+ { IDS_MI_INIT_ERR_DEBUGSESSIONINFO, "LLDB debug session info. %s " },
+ { IDS_MI_INIT_ERR_THREADMANAGER, "Unable to init thread manager." },
+ { IDS_MI_INIT_ERR_CLIENT_USING_DRIVER, "Initialising the client to this driver failed." },
+ { IDS_MI_INIT_ERR_LOCAL_DEBUG_SESSION, "Initialising a local debug session failed." },
+ { IDS_CODE_ERR_INVALID_PARAMETER_VALUE, "Code. Invalid parameter passed to function '%s'" },
+ { IDS_CODE_ERR_INVALID_PARAM_NULL_POINTER, "Code. NULL pointer passes as a parameter to function '%s'" },
+ { IDS_CODE_ERR_INVALID_ENUMERATION_VALUE, "Code. Invalid enumeration value encountered in function '%s'" },
+ { IDS_LLDBDEBUGGER_ERR_INVALIDLISTENER, "LLDB Debugger. LLDB Listener is not valid", },
+ { IDS_LLDBDEBUGGER_ERR_INVALIDDEBUGGER, "LLDB Debugger. LLDB Debugger is not valid", },
+ { IDS_LLDBDEBUGGER_ERR_CLIENTDRIVER, "LLDB Debugger. CMIDriverBase derived driver needs to be set prior to CMICmnLLDBDDebugger initialisation" },
+ { IDS_LLDBDEBUGGER_ERR_STARTLISTENER, "LLDB Debugger. Starting listening events for '%s' failed" },
+ { IDS_LLDBDEBUGGER_ERR_THREADCREATIONFAIL, "LLDB Debugger. Thread creation failed '%s'" },
+ { IDS_LLDBDEBUGGER_ERR_THREAD_DELETE, "LLDB Debugger. Thread failed to delete '%s'" },
+ { IDS_LLDBDEBUGGER_ERR_INVALIDBROADCASTER, "LLDB Debugger. Invalid SB broadcaster class name '%s' " },
+ { IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME, "LLDB Debugger. Invalid client name '%s' " },
+ { IDS_LLDBDEBUGGER_ERR_CLIENTNOTREGISTERD, "LLDB Debugger. Client name '%s' not registered for listening events" },
+ { IDS_LLDBDEBUGGER_ERR_STOPLISTENER, "LLDB Debugger. Failure occurred stopping event for client '%s' SBBroadcaster '%s'" },
+ { IDS_LLDBDEBUGGER_ERR_BROARDCASTER_NAME, "LLDB Debugger. Broardcaster's name '%s' is not valid" },
+ { IDS_LLDBDEBUGGER_WRN_UNKNOWN_EVENT, "LLDB Debugger. Unhandled event '%s'" },
+ { IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT, "LLDB Out-of-band. Handling event for '%s', an event enumeration '%d' not recognised" },
+ { IDS_LLDBOUTOFBAND_ERR_PROCESS_INVALID, "LLDB Out-of-band. Invalid '%s' in '%s'" },
+ { IDS_LLDBOUTOFBAND_ERR_BRKPT_NOTFOUND, "LLDB Out-of-band. %s. Breakpoint information for breakpoint ID %d not found" },
+ { IDS_LLDBOUTOFBAND_ERR_BRKPT_INFO_GET, "LLDB Out-of-band. %s. Failed to retrieve breakpoint information for for breakpoint ID %d" },
+ { IDS_LLDBOUTOFBAND_ERR_BRKPT_INFO_SET, "LLDB Out-of-band. %s. Failed to set breakpoint information for for breakpoint ID %d" },
+ { IDS_LLDBOUTOFBAND_ERR_FORM_MI_RESPONSE, "LLDB Out-of-band. %s. Failed to form the MI Out-of-band response" },
+ { IDS_LLDBOUTOFBAND_ERR_FRAME_INFO_GET, "LLDB Out-of-band. %s. Failed to retrieve frame information" },
+ { IDS_LLDBOUTOFBAND_ERR_SETNEWDRIVERSTATE, "LLDB Out-of-band. %s. Event handler tried to set new MI Driver running state and failed. %s" },
+ { IDS_LLDBOUTOFBAND_ERR_BRKPT_CNT_EXCEEDED, "LLDB Out-of-band. '%s'. Number of valid breakpoint exceeded %d. Cannot create new breakpoint with ID %d" },
+ { IDS_DBGSESSION_ERR_SHARED_DATA_RELEASE, "LLDB debug session info. Release some or all of the data shared across command instances failed" },
+ { IDS_DBGSESSION_ERR_SHARED_DATA_ADD, "LLDB debug session info. Failed to add '%s' data to the shared data command container" },
+ { IDS_MI_SHTDWN_ERR_LOG, "Log. Error occurred during shutdown. %s" },
+ { IDS_MI_SHUTDOWN_ERR, "Server shutdown failure. %s" },
+ { IDE_MI_SHTDWN_ERR_RESOURCES, "Resources. Error occurred during shutdown. %s" },
+ { IDE_MI_SHTDWN_ERR_STREAMSTDIN, "Stdin. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER, "Stdin handler. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_STREAMSTDOUT, "Stdout. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_STREAMSTDERR, "Stderr. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_THREADMGR, "Thread Mgr. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_CMDINTERPRETER, "Command interpreter. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_CMDMGR, "Command manager. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_CMDFACTORY, "Command factory. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_CMDMONITOR, "Command invoker. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_CMDINVOKER, "Command monitor. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_LLDBDEBUGGER, "LLDB Debugger. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_DRIVERMGR, "Driver manager. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_DRIVER, "Driver. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_OUTOFBANDHANDLER, "Out-of-band handler. Error occurred during shutdown. %s" },
+ { IDS_MI_SHTDWN_ERR_DEBUGSESSIONINFO, "LLDB debug session info. Error occurred during shutdown. %s" },
+ { IDE_MI_SHTDWN_ERR_THREADMANAGER, "Unable to shutdown thread manager" },
+ { IDS_DRIVER_ERR_PARSE_ARGS, "Driver. Driver '%s'. Parse args error '%s'" },
+ { IDS_DRIVER_ERR_PARSE_ARGS_UNKNOWN, "Driver. Driver '%s'. Parse args error unknown" },
+ { IDS_DRIVER_ERR_CURRENT_NOT_SET, "Driver. Current working driver has not been set. Call CMIDriverMgr::SetUseThisDriverToDoWork()" },
+ { IDS_DRIVER_ERR_NON_REGISTERED, "Driver. No suitable drivers registered with the CMIDriverMgr to do work" },
+ { IDS_DRIVER_SAY_DRIVER_USING, "Driver. Using driver '%s' internally" },
+ { IDS_DRIVER_ERR_ID_INVALID, "Driver. Driver '%s' invalid ID '%s'" },
+ { IDS_DRIVER_ERR_FALLTHRU_DRIVER_ERR, "Driver. Fall through driver '%s' (ID:'%s') error '%s'" },
+ { IDS_DRIVER_CMD_RECEIVED, "Driver. Received command '%s'. It was %shandled%s" },
+ { IDS_DRIVER_CMD_NOT_IN_FACTORY, ". Command '%s' not in Command Factory" },
+ { IDS_DRIVER_ERR_DRIVER_STATE_ERROR, "Driver. Driver running state error. Cannot go to next state from present state as not allowed", },
+ { IDS_DRIVER_WAITING_STDIN_DATA, "Driver. Main thread suspended waiting on Stdin Monitor to resume main thread" },
+ { IDS_DRIVER_ERR_MAINLOOP, "Driver. Error in do main loop. %s" },
+ { IDS_DRIVER_ERR_LOCAL_DEBUG_NOT_IMPL, "Driver. --executable argument given. Local debugging is not implemented." },
+ { IDS_DRIVER_ERR_LOCAL_DEBUG_INIT, "Driver. --executable argument given. Initialising local debugging failed." },
+ { IDS_STDOUT_ERR_NOT_ALL_DATA_WRITTEN, "Stdout. Not all data was written to stream. The data '%s'" },
+ { IDS_STDERR_ERR_NOT_ALL_DATA_WRITTEN, "Stderr. Not all data was written to stream. The data '%s'" },
+ { IDS_CMD_ARGS_ERR_N_OPTIONS_REQUIRED, "Command Args. Missing options, %d or more required" },
+ { IDS_CMD_ARGS_ERR_OPTION_NOT_FOUND, "Command Args. Option '%s' not found" },
+ { IDS_CMD_ARGS_ERR_VALIDATION_MANDATORY, "Mandatory args not found: %s" },
+ { IDS_CMD_ARGS_ERR_VALIDATION_INVALID, "Invalid args: %s" },
+ { IDS_CMD_ARGS_ERR_VALIDATION_MAN_INVALID, "Mandatory args not found: %s. Invalid args: %s" },
+ { IDS_CMD_ARGS_ERR_VALIDATION_MISSING_INF, "Args missing additional information: %s" },
+ { IDS_CMD_ARGS_ERR_CONTEXT_NOT_ALL_EATTEN, "Not all arguments or options were recognised: %s" },
+ { IDS_CMD_ARGS_ERR_PREFIX_MSG, "Command Args. Validation failed. " },
+ { IDS_VARIANT_ERR_USED_BASECLASS, "Variant container: Variant object used the base class. See CMIUtilVariant" },
+ { IDS_VARIANT_ERR_MAP_KEY_INVALID, "Variant container: Invalid ID '%s'" },
+ { IDS_WORD_INVALIDBRKTS, "<Invalid>" },
+ { IDS_WORD_NONE, "None" },
+ { IDS_WORD_NOT, "not" },
+ { IDS_WORD_INVALIDEMPTY, "<empty>" },
+ { IDS_WORD_INVALIDNULLPTR, "<NULL ptr>" },
+ { IDS_WORD_UNKNOWNBRKTS, "<unknown>" },
+ { IDS_WORD_NOT_IMPLEMENTED, "Not implemented" },
+ { IDS_WORD_NOT_IMPLEMENTED_BRKTS, "<not implemented>" },
+ { IDS_WORD_UNKNOWNTYPE_BRKTS, "<unknowntype>" },
+ { IDS_WORD_ERR_MSG_NOT_IMPLEMENTED_BRKTS, "<error message not implemented>" },
+ { IDS_CMD_ERR_N_OPTIONS_REQUIRED, "Command '%s'. Missing options, %d required" },
+ { IDS_CMD_ERR_OPTION_NOT_FOUND, "Command '%s'. Option '%s' not found" },
+ { IDS_CMD_ERR_ARGS, "Command '%s'. %s" },
+ { IDS_CMD_WRN_ARGS_NOT_HANDLED, "Command '%s'. Warning the following options not handled by the command: %s" },
+ { IDS_CMD_ERR_FNFAILED, "Command '%s'. Fn '%s' failed" },
+ { IDS_CMD_ERR_SHARED_DATA_NOT_FOUND, "Command '%s'. Shared data '%s' not found" },
+ { IDS_CMD_ERR_LLDBPROCESS_DETACH, "Command '%s'. Process detach failed. '%s'" },
+ { IDS_CMD_ERR_SETWKDIR, "Command '%s'. Failed to set working directory '%s'" },
+ { IDS_CMD_ERR_INVALID_TARGET, "Command '%s'. Target binary '%s' is invalid. %s" },
+ { IDS_CMD_ERR_INVALID_TARGET_CURRENT, "Command '%s'. Current SBTarget is invalid" },
+ { IDS_CMD_ERR_INVALID_TARGET_TYPE, "Command '%s'. Target type '%s' is not recognised" },
+ { IDS_CMD_ERR_INVALID_TARGET_PLUGIN, "Command '%s'. Target plugin is invalid. %s" },
+ { IDS_CMD_ERR_CONNECT_TO_TARGET, "Command '%s'. Error connecting to target: '%s'" },
+ { IDS_CMD_ERR_INVALID_TARGETPLUGINCURRENT, "Command '%s'. Current target plugin is invalid" },
+ { IDS_CMD_ERR_NOT_IMPLEMENTED, "Command '%s'. Command not implemented" },
+ { IDS_CMD_ERR_NOT_IMPLEMENTED_DEPRECATED, "Command '%s'. Command not implemented as it has been deprecated" },
+ { IDS_CMD_ERR_CREATE_TARGET, "Command '%s'. Create target failed: %s" },
+ { IDS_CMD_ERR_BRKPT_LOCATION_FORMAT, "Command '%s'. Incorrect format for breakpoint location '%s'" },
+ { IDS_CMD_ERR_BRKPT_INVALID, "Command '%s'. Breakpoint '%s' invalid" },
+ { IDS_CMD_ERR_BRKPT_CNT_EXCEEDED, "Command '%s'. Number of valid breakpoint exceeded %d. Cannot create new breakpoint '%s'" },
+ { IDS_CMD_ERR_SOME_ERROR, "Command '%s'. Error: %s" },
+ { IDS_CMD_ERR_THREAD_INVALID, "Command '%s'. Thread ID invalid" },
+ { IDS_CMD_ERR_THREAD_FRAME_RANGE_INVALID, "Command '%s'. Thread frame range invalid" },
+ { IDS_CMD_ERR_FRAME_INVALID, "Command '%s'. Frame ID invalid" },
+ { IDS_CMD_ERR_VARIABLE_DOESNOTEXIST, "Command '%s'. Variable '%s' does not exist" },
+ { IDS_CMD_ERR_VARIABLE_ENUM_INVALID, "Command '%s'. Invalid enumeration for variable '%s' formatted string '%s'" },
+ { IDS_CMD_ERR_VARIABLE_EXPRESSIONPATH, "Command '%s'. Failed to get expression for variable '%s'" },
+ { IDS_CMD_ERR_VARIABLE_CREATION_FAILED, "Failed to create variable object for '%s'" },
+ { IDS_CMD_ERR_CMD_RUN_BUT_NO_ACTION, "<Error: Command run but command did not do anything useful. No MI response formed>" },
+ { IDS_CMD_ERR_EVENT_HANDLED_BUT_NO_ACTION, "<Error: Command run and event caught, did nothing useful. No MI Out-of-Bound formed>"},
+ { IDS_CMD_ERR_DISASM_ADDR_START_INVALID, "Command '%s'. Invalid start value '%s'" },
+ { IDS_CMD_ERR_DISASM_ADDR_END_INVALID, "Command '%s'. Invalid end value '%s'" },
+ { IDS_CMD_ERR_MEMORY_ALLOC_FAILURE, "Command '%s'. Failed to allocate memory %d bytes" },
+ { IDS_CMD_ERR_LLDB_ERR_NOT_READ_WHOLE_BLK, "Command '%s'. LLDB unable to read entire memory block of %u bytes at address 0x%08x" },
+ { IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES, "Command '%s'. Unable to read memory block of %u bytes at address 0x%08x: %s " },
+ { IDS_CMD_ERR_INVALID_PROCESS, "Command '%s'. Invalid process during debug session" },
+ { IDS_CMD_ERR_INVALID_FORMAT_TYPE, "Command '%s'. Invalid var format type '%s'" },
+ { IDS_CMD_ERR_BRKPT_INFO_OBJ_NOT_FOUND, "Command '%s'. Breakpoint information for breakpoint ID %d not found" },
+ { IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES, "Command '%s'. Unable to write memory block of %u bytes at address 0x%08x: %s " },
+ { IDS_CMD_ERR_LLDB_ERR_NOT_WRITE_WHOLEBLK, "Command '%s'. LLDB unable to write entire memory block of %u bytes at address 0x%08x" },
+ { IDS_CMD_ERR_SET_NEW_DRIVER_STATE, "Command '%s'. Command tried to set new MI Driver running state and failed. %s" },
+ { IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND, "The request '%s' was not recogised, not implemented" },
+ { IDS_CMD_ERR_INFO_PRINTFN_FAILED, "The request '%s' failed." },
+ { IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH, "'solib-search-path' requires at least one argument" }
+ };
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnResources constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnResources::CMICmnResources( void )
+: m_nResourceId2TextDataSize( 0 )
+{
+ // Do not use this constructor, use Initialize()
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnResources destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnResources::~CMICmnResources( void )
+{
+ // Do not use this destructor, use Shutdown()
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize the resources and set locality for the server.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnResources::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = ReadResourceStringData();
+
+ return m_bInitialized;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this object.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnResources::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ // Tear down resource explicitly
+ m_mapRscrIdToTextData.clear();
+
+ m_bInitialized = false;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize the resources and set locality for the server.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnResources::ReadResourceStringData( void )
+{
+ m_nResourceId2TextDataSize = sizeof ms_pResourceId2TextData / sizeof ms_pResourceId2TextData[ 0 ];
+ for( MIuint i = 0; i < m_nResourceId2TextDataSize; i++ )
+ {
+ const SRsrcTextData * pRscrData = &ms_pResourceId2TextData[ i ];
+ MapPairRscrIdToTextData_t pr( pRscrData->id, pRscrData->pTextData );
+ m_mapRscrIdToTextData.insert( pr );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the corresponding text assigned to the resource ID.
+// Type: Method.
+// Args: vResourceId - (R) MI resource ID.
+// Return: CMIUtilString - Resource text.
+// Throws: None.
+//--
+CMIUtilString CMICmnResources::GetString( const MIuint vResourceId ) const
+{
+ CMIUtilString str;
+ const bool bFound = GetStringFromResource( vResourceId, str ); MIunused( bFound );
+ assert( bFound );
+
+ return str;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine the MI resource ID existings.
+// Type: Method.
+// Args: vResourceId - (R) MI resource ID.
+// Return: True - Exists.
+// False - Not found.
+// Throws: None.
+//--
+bool CMICmnResources::HasString( const MIuint vResourceId ) const
+{
+ CMIUtilString str;
+ return GetStringFromResource( vResourceId, str );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the resource text data for the given resource ID. If a resourse ID
+// cannot be found and error is given returning the ID of the resource that
+// cannot be located.
+// Type: Method.
+// Args: vResourceId - (R) MI resource ID.
+// vrwResourceString - (W) Text.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnResources::GetStringFromResource( const MIuint vResourceId, CMIUtilString & vrwResourceString ) const
+{
+ MapRscrIdToTextData_t::const_iterator it = m_mapRscrIdToTextData.find( vResourceId );
+ if( it == m_mapRscrIdToTextData.end() )
+ {
+ // Check this is a static variable init that needs this before we are ready
+ if( !m_bInitialized )
+ {
+ (const_cast< CMICmnResources * >( this ))->Initialize();
+ it = m_mapRscrIdToTextData.find( vResourceId );
+ if( it == m_mapRscrIdToTextData.end() )
+ {
+ vrwResourceString = MIRSRC( IDS_RESOURCES_ERR_STRING_TABLE_INVALID );
+ return MIstatus::failure;
+ }
+ }
+
+ if( it == m_mapRscrIdToTextData.end() )
+ {
+ vrwResourceString = CMIUtilString::Format( MIRSRC( IDS_RESOURCES_ERR_STRING_NOT_FOUND ), vResourceId );
+ return MIstatus::failure;
+ }
+ }
+
+ const MIuint nRsrcId( (*it).first ); MIunused( nRsrcId );
+ const MIchar * pRsrcData( (*it).second );
+
+ // Return result
+ vrwResourceString = pRsrcData;
+
+ return MIstatus::success;
+}
+
diff --git a/tools/lldb-mi/MICmnResources.h b/tools/lldb-mi/MICmnResources.h
new file mode 100644
index 000000000000..f836f8d1b8aa
--- /dev/null
+++ b/tools/lldb-mi/MICmnResources.h
@@ -0,0 +1,351 @@
+//===-- MICmnResources.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnResources.h
+//
+// Overview: CMICmnResources interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers
+#include <map>
+
+// In-house headers:
+#include "MIUtilSingletonBase.h"
+#include "MIUtilString.h"
+#include "MICmnBase.h"
+
+//++ ============================================================================
+// Details: MI string test data resource definitions. These IDs match up with
+// actual string data in a map internal to CMICmnResources.
+// *** Be sure to update ms_pResourceId2TextData[] array ****
+enum
+{
+ IDS_PROJNAME = 1,
+ IDS_MI_VERSION_DESCRIPTION_DEBUG ,
+ IDS_MI_VERSION_DESCRIPTION ,
+ IDS_MI_APPNAME_SHORT ,
+ IDS_MI_APPNAME_LONG ,
+ IDS_MI_APP_FILEPATHNAME ,
+ IDS_MI_APP_ARGS ,
+ IDE_MI_VERSION_GDB ,
+
+ IDS_UTIL_FILE_ERR_INVALID_PATHNAME ,
+ IDS_UTIL_FILE_ERR_OPENING_FILE ,
+ IDS_UTIL_FILE_ERR_OPENING_FILE_UNKNOWN ,
+ IDE_UTIL_FILE_ERR_WRITING_FILE ,
+ IDE_UTIL_FILE_ERR_WRITING_NOTOPEN ,
+
+ IDS_RESOURCES_ERR_STRING_NOT_FOUND ,
+ IDS_RESOURCES_ERR_STRING_TABLE_INVALID ,
+
+ IDS_MI_CLIENT_MSG ,
+
+ IDS_LOG_MSG_CREATION_DATE ,
+ IDS_LOG_MSG_FILE_LOGGER_PATH ,
+ IDS_LOG_MSG_VERSION ,
+ IDS_LOG_ERR_FILE_LOGGER_DISABLED ,
+ IDS_LOG_MEDIUM_ERR_INIT ,
+ IDS_LOG_MEDIUM_ERR_WRITE_ANY ,
+ IDS_LOG_MEDIUM_ERR_WRITE_MEDIUMFAIL ,
+ IDE_MEDIUMFILE_ERR_GET_FILE_PATHNAME_SYS,
+
+ IDS_MEDIUMFILE_NAME ,
+ IDS_MEDIUMFILE_ERR_INVALID_PATH ,
+ IDS_MEDIUMFILE_ERR_FILE_HEADER ,
+ IDS_MEDIUMFILE_NAME_LOG ,
+
+ IDE_OS_ERR_UNKNOWN ,
+ IDE_OS_ERR_RETRIEVING ,
+
+ IDS_DRIVERMGR_DRIVER_ERR_INIT ,
+
+ IDE_MEDIUMSTDERR_NAME ,
+ IDE_MEDIUMSTDOUT_NAME ,
+
+ IDE_MI_APP_EXIT_OK ,
+ IDE_MI_APP_EXIT_WITH_PROBLEM ,
+ IDE_MI_APP_EXIT_WITH_PROBLEM_NO_LOG ,
+
+ IDE_MI_APP_DESCRIPTION ,
+ IDE_MI_APP_INFORMATION ,
+ IDE_MI_APP_ARG_USAGE ,
+ IDE_MI_APP_ARG_HELP ,
+ IDE_MI_APP_ARG_VERSION ,
+ IDE_MI_APP_ARG_VERSION_LONG ,
+ IDE_MI_APP_ARG_INTERPRETER ,
+ IDE_MI_APP_ARG_EXECUTEABLE ,
+ IDE_MI_APP_ARG_NO_APP_LOG ,
+ IDE_MI_APP_ARG_EXAMPLE ,
+ IDE_MI_APP_ARG_EXECUTABLE ,
+
+ IDS_STDIN_ERR_INVALID_PROMPT ,
+ IDS_STDIN_ERR_THREAD_CREATION_FAILED ,
+ IDS_STDIN_ERR_THREAD_DELETE ,
+ IDS_STDIN_ERR_CHKING_BYTE_AVAILABLE ,
+ IDS_STDIN_INPUT_CTRL_CHARS ,
+
+ IDS_CMD_QUIT_HELP ,
+
+ IDS_THREADMGR_ERR_THREAD_ID_INVALID ,
+ IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ,
+ IDS_THREADMGR_ERR_THREAD_ID_NOT_FOUND ,
+ IDS_THREADMGR_ERR_THREAD_STILL_ALIVE ,
+
+ IDS_FALLTHRU_DRIVER_CMD_RECEIVED ,
+
+ IDS_CMDFACTORY_ERR_INVALID_CMD_NAME ,
+ IDS_CMDFACTORY_ERR_INVALID_CMD_CR8FN ,
+ IDS_CMDFACTORY_ERR_CMD_NOT_REGISTERED ,
+ IDS_CMDFACTORY_ERR_CMD_ALREADY_REGED ,
+
+ IDS_CMDMGR_ERR_CMD_FAILED_CREATE ,
+ IDS_CMDMGR_ERR_CMD_INVOKER ,
+
+ IDS_PROCESS_SIGNAL_RECEIVED ,
+
+ IDS_MI_INIT_ERR_LOG ,
+ IDS_MI_INIT_ERR_RESOURCES ,
+ IDS_MI_INIT_ERR_INIT ,
+ IDS_MI_INIT_ERR_STREAMSTDIN ,
+ IDS_MI_INIT_ERR_STREAMSTDIN_OSHANDLER ,
+ IDS_MI_INIT_ERR_OS_STDIN_HANDLER ,
+ IDS_MI_INIT_ERR_STREAMSTDOUT ,
+ IDS_MI_INIT_ERR_STREAMSTDERR ,
+ IDS_MI_INIT_ERR_FALLTHRUDRIVER ,
+ IDS_MI_INIT_ERR_THREADMGR ,
+ IDS_MI_INIT_ERR_CMDINTERPRETER ,
+ IDS_MI_INIT_ERR_CMDMGR ,
+ IDS_MI_INIT_ERR_CMDFACTORY ,
+ IDS_MI_INIT_ERR_CMDINVOKER ,
+ IDS_MI_INIT_ERR_CMDMONITOR ,
+ IDS_MI_INIT_ERR_LLDBDEBUGGER ,
+ IDS_MI_INIT_ERR_DRIVERMGR ,
+ IDS_MI_INIT_ERR_DRIVER ,
+ IDS_MI_INIT_ERR_OUTOFBANDHANDLER ,
+ IDS_MI_INIT_ERR_DEBUGSESSIONINFO ,
+ IDS_MI_INIT_ERR_THREADMANAGER ,
+ IDS_MI_INIT_ERR_CLIENT_USING_DRIVER ,
+ IDS_MI_INIT_ERR_LOCAL_DEBUG_SESSION ,
+
+ IDS_CODE_ERR_INVALID_PARAMETER_VALUE ,
+ IDS_CODE_ERR_INVALID_PARAM_NULL_POINTER ,
+ IDS_CODE_ERR_INVALID_ENUMERATION_VALUE ,
+
+ IDS_LLDBDEBUGGER_ERR_INVALIDLISTENER ,
+ IDS_LLDBDEBUGGER_ERR_INVALIDDEBUGGER ,
+ IDS_LLDBDEBUGGER_ERR_CLIENTDRIVER ,
+ IDS_LLDBDEBUGGER_ERR_STARTLISTENER ,
+ IDS_LLDBDEBUGGER_ERR_THREADCREATIONFAIL ,
+ IDS_LLDBDEBUGGER_ERR_THREAD_DELETE ,
+ IDS_LLDBDEBUGGER_ERR_INVALIDBROADCASTER ,
+ IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME ,
+ IDS_LLDBDEBUGGER_ERR_CLIENTNOTREGISTERD ,
+ IDS_LLDBDEBUGGER_ERR_STOPLISTENER ,
+ IDS_LLDBDEBUGGER_ERR_BROARDCASTER_NAME ,
+ IDS_LLDBDEBUGGER_WRN_UNKNOWN_EVENT ,
+
+ IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT ,
+ IDS_LLDBOUTOFBAND_ERR_PROCESS_INVALID ,
+ IDS_LLDBOUTOFBAND_ERR_BRKPT_NOTFOUND ,
+ IDS_LLDBOUTOFBAND_ERR_BRKPT_INFO_GET ,
+ IDS_LLDBOUTOFBAND_ERR_BRKPT_INFO_SET ,
+ IDS_LLDBOUTOFBAND_ERR_FORM_MI_RESPONSE ,
+ IDS_LLDBOUTOFBAND_ERR_FRAME_INFO_GET ,
+ IDS_LLDBOUTOFBAND_ERR_SETNEWDRIVERSTATE ,
+ IDS_LLDBOUTOFBAND_ERR_BRKPT_CNT_EXCEEDED,
+
+
+ IDS_DBGSESSION_ERR_SHARED_DATA_RELEASE ,
+ IDS_DBGSESSION_ERR_SHARED_DATA_ADD ,
+
+ IDS_MI_SHTDWN_ERR_LOG ,
+ IDS_MI_SHUTDOWN_ERR ,
+ IDE_MI_SHTDWN_ERR_RESOURCES ,
+ IDE_MI_SHTDWN_ERR_STREAMSTDIN ,
+ IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER ,
+ IDS_MI_SHTDWN_ERR_STREAMSTDOUT ,
+ IDS_MI_SHTDWN_ERR_STREAMSTDERR ,
+ IDS_MI_SHTDWN_ERR_THREADMGR ,
+ IDS_MI_SHTDWN_ERR_CMDINTERPRETER ,
+ IDS_MI_SHTDWN_ERR_CMDMGR ,
+ IDS_MI_SHTDWN_ERR_CMDFACTORY ,
+ IDS_MI_SHTDWN_ERR_CMDINVOKER ,
+ IDS_MI_SHTDWN_ERR_CMDMONITOR ,
+ IDS_MI_SHTDWN_ERR_LLDBDEBUGGER ,
+ IDS_MI_SHTDWN_ERR_DRIVERMGR ,
+ IDS_MI_SHTDWN_ERR_DRIVER ,
+ IDS_MI_SHTDWN_ERR_OUTOFBANDHANDLER ,
+ IDS_MI_SHTDWN_ERR_DEBUGSESSIONINFO ,
+ IDE_MI_SHTDWN_ERR_THREADMANAGER ,
+
+ IDS_DRIVER_ERR_PARSE_ARGS ,
+ IDS_DRIVER_ERR_PARSE_ARGS_UNKNOWN ,
+ IDS_DRIVER_ERR_CURRENT_NOT_SET ,
+ IDS_DRIVER_ERR_NON_REGISTERED ,
+ IDS_DRIVER_SAY_DRIVER_USING ,
+ IDS_DRIVER_ERR_ID_INVALID ,
+ IDS_DRIVER_ERR_FALLTHRU_DRIVER_ERR ,
+ IDS_DRIVER_CMD_RECEIVED ,
+ IDS_DRIVER_CMD_NOT_IN_FACTORY ,
+ IDS_DRIVER_ERR_DRIVER_STATE_ERROR ,
+ IDS_DRIVER_ERR_MAINLOOP ,
+ IDS_DRIVER_ERR_LOCAL_DEBUG_NOT_IMPL ,
+ IDS_DRIVER_ERR_LOCAL_DEBUG_INIT ,
+
+ IDS_DRIVER_WAITING_STDIN_DATA ,
+
+ IDS_STDOUT_ERR_NOT_ALL_DATA_WRITTEN ,
+ IDS_STDERR_ERR_NOT_ALL_DATA_WRITTEN ,
+
+ IDS_CMD_ARGS_ERR_N_OPTIONS_REQUIRED ,
+ IDS_CMD_ARGS_ERR_OPTION_NOT_FOUND ,
+ IDS_CMD_ARGS_ERR_VALIDATION_MANDATORY ,
+ IDS_CMD_ARGS_ERR_VALIDATION_INVALID ,
+ IDS_CMD_ARGS_ERR_VALIDATION_MAN_INVALID ,
+ IDS_CMD_ARGS_ERR_VALIDATION_MISSING_INF ,
+ IDS_CMD_ARGS_ERR_CONTEXT_NOT_ALL_EATTEN ,
+ IDS_CMD_ARGS_ERR_PREFIX_MSG ,
+
+ IDS_VARIANT_ERR_USED_BASECLASS ,
+ IDS_VARIANT_ERR_MAP_KEY_INVALID,
+
+ IDS_WORD_INVALIDBRKTS ,
+ IDS_WORD_NONE ,
+ IDS_WORD_NOT ,
+ IDS_WORD_INVALIDEMPTY ,
+ IDS_WORD_INVALIDNULLPTR ,
+ IDS_WORD_UNKNOWNBRKTS ,
+ IDS_WORD_NOT_IMPLEMENTED ,
+ IDS_WORD_NOT_IMPLEMENTED_BRKTS ,
+ IDS_WORD_UNKNOWNTYPE_BRKTS ,
+ IDS_WORD_ERR_MSG_NOT_IMPLEMENTED_BRKTS ,
+
+ IDS_CMD_ERR_N_OPTIONS_REQUIRED ,
+ IDS_CMD_ERR_OPTION_NOT_FOUND ,
+ IDS_CMD_ERR_ARGS ,
+ IDS_CMD_WRN_ARGS_NOT_HANDLED ,
+ IDS_CMD_ERR_FNFAILED ,
+ IDS_CMD_ERR_SHARED_DATA_NOT_FOUND ,
+ IDS_CMD_ERR_LLDBPROCESS_DETACH ,
+ IDS_CMD_ERR_SETWKDIR ,
+ IDS_CMD_ERR_INVALID_TARGET ,
+ IDS_CMD_ERR_INVALID_TARGET_CURRENT ,
+ IDS_CMD_ERR_INVALID_TARGET_TYPE ,
+ IDS_CMD_ERR_INVALID_TARGET_PLUGIN ,
+ IDS_CMD_ERR_CONNECT_TO_TARGET ,
+ IDS_CMD_ERR_INVALID_TARGETPLUGINCURRENT ,
+ IDS_CMD_ERR_NOT_IMPLEMENTED ,
+ IDS_CMD_ERR_NOT_IMPLEMENTED_DEPRECATED ,
+ IDS_CMD_ERR_CREATE_TARGET ,
+ IDS_CMD_ERR_BRKPT_LOCATION_FORMAT ,
+ IDS_CMD_ERR_BRKPT_INVALID ,
+ IDS_CMD_ERR_BRKPT_CNT_EXCEEDED ,
+ IDS_CMD_ERR_SOME_ERROR ,
+ IDS_CMD_ERR_THREAD_INVALID ,
+ IDS_CMD_ERR_THREAD_FRAME_RANGE_INVALID ,
+ IDS_CMD_ERR_FRAME_INVALID ,
+ IDS_CMD_ERR_VARIABLE_DOESNOTEXIST ,
+ IDS_CMD_ERR_VARIABLE_ENUM_INVALID ,
+ IDS_CMD_ERR_VARIABLE_EXPRESSIONPATH ,
+ IDS_CMD_ERR_VARIABLE_CREATION_FAILED ,
+ IDS_CMD_ERR_CMD_RUN_BUT_NO_ACTION ,
+ IDS_CMD_ERR_EVENT_HANDLED_BUT_NO_ACTION ,
+ IDS_CMD_ERR_DISASM_ADDR_START_INVALID ,
+ IDS_CMD_ERR_DISASM_ADDR_END_INVALID ,
+ IDS_CMD_ERR_MEMORY_ALLOC_FAILURE ,
+ IDS_CMD_ERR_LLDB_ERR_NOT_READ_WHOLE_BLK ,
+ IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES ,
+ IDS_CMD_ERR_INVALID_PROCESS ,
+ IDS_CMD_ERR_INVALID_FORMAT_TYPE ,
+ IDS_CMD_ERR_BRKPT_INFO_OBJ_NOT_FOUND ,
+ IDS_CMD_ERR_LLDB_ERR_WRITE_MEM_BYTES ,
+ IDS_CMD_ERR_LLDB_ERR_NOT_WRITE_WHOLEBLK ,
+ IDS_CMD_ERR_SET_NEW_DRIVER_STATE ,
+ IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND ,
+ IDS_CMD_ERR_INFO_PRINTFN_FAILED ,
+ IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH
+};
+
+//++ ============================================================================
+// Details: MI common code implementation class. Handle application resources
+// and locality.
+// Singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 29/01/2014.
+// Changes: None.
+//--
+class CMICmnResources
+: public CMICmnBase
+, public MI::ISingleton< CMICmnResources >
+{
+ friend class MI::ISingleton< CMICmnResources >;
+
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+
+ CMIUtilString GetString( const MIuint vResourceId ) const;
+ bool HasString( const MIuint vResourceId ) const;
+
+// Typedef:
+private:
+ typedef std::map< MIuint, const MIchar * > MapRscrIdToTextData_t;
+ typedef std::pair< MIuint, const MIchar * > MapPairRscrIdToTextData_t;
+
+// Enumerations:
+private:
+ enum Buffer_e
+ {
+ eBufferSize = 2048
+ };
+
+// Structs:
+private:
+ struct SRsrcTextData
+ {
+ MIuint id;
+ const MIchar * pTextData;
+ };
+
+// Methods:
+private:
+ /* ctor */ CMICmnResources( void );
+ /* ctor */ CMICmnResources( const CMICmnResources & );
+ void operator=( const CMICmnResources & );
+
+ bool GetStringFromResource( const MIuint vResourceId, CMIUtilString & vrwResourceString ) const;
+ bool ReadResourceStringData( void );
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnResources( void );
+
+// Attributes:
+private:
+ static const SRsrcTextData ms_pResourceId2TextData[];
+ //
+ MIuint m_nResourceId2TextDataSize;
+ MapRscrIdToTextData_t m_mapRscrIdToTextData;
+};
+
+//++ =========================================================================
+// Details: Macro short cut for retrieving a text data resource
+//--
+#define MIRSRC( x ) CMICmnResources::Instance().GetString( x ).c_str()
diff --git a/tools/lldb-mi/MICmnStreamStderr.cpp b/tools/lldb-mi/MICmnStreamStderr.cpp
new file mode 100644
index 000000000000..1d66110eab07
--- /dev/null
+++ b/tools/lldb-mi/MICmnStreamStderr.cpp
@@ -0,0 +1,257 @@
+//===-- MICmnStreamStderr.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnStreamStderr.cpp
+//
+// Overview: CMICmnStreamStderr implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnStreamStderr.h"
+#include "MICmnLog.h"
+#include "MICmnResources.h"
+#include "MIDriver.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnStreamStderr constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnStreamStderr::CMICmnStreamStderr( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnStreamStderr destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnStreamStderr::~CMICmnStreamStderr( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this stderr stream.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStderr::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+
+#ifdef _MSC_VER
+ // Debugging / I/O issues with client.
+ // This is only required on Windows if you do not use ::flush(stderr). MI uses
+ // ::flush(stderr)
+ // It trys to ensure the process attached to the stderr steam gets ALL the data.
+ //::setbuf( stderr, NULL );
+#endif // _MSC_VER
+
+ m_bInitialized = bOk;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this stderr stream.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStderr::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ ClrErrorDescription();
+
+ m_bInitialized = false;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Write text data to stderr. Prefix the message with "MI:". The text data does
+// not need to include a carrage line return as this is added to the text. The
+// function also then passes the text data into the CMICmnLog logger.
+// Type: Method.
+// Args: vText - (R) Text data.
+// vbSendToLog - (R) True = Yes send to the Log file too, false = do not. (Dflt = true)
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStderr::Write( const CMIUtilString & vText, const bool vbSendToLog /* = true */ )
+{
+ if( vText.length() == 0 )
+ return MIstatus::failure;
+
+ const CMIUtilString strPrefixed( CMIUtilString::Format( "%s: %s", CMIDriver::Instance().GetAppNameShort().c_str(), vText.c_str() ) );
+
+ return WritePriv( strPrefixed, vText, vbSendToLog );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Write an LLDB text message to stderr.
+// The text data does not need to include a carrage line return as this is added
+// to the text. The function also then passes the text data into the CMICmnLog
+// logger.
+// Type: Method.
+// Args: vText - (R) Text data.
+// vbSendToLog - (R) True = Yes send to the Log file too, false = do not. (Dflt = true)
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStderr::WriteLLDBMsg( const CMIUtilString & vText, const bool vbSendToLog /* = true */ )
+{
+ if( vText.length() == 0 )
+ return MIstatus::failure;
+
+ const CMIUtilString strPrefixed( CMIUtilString::Format( "LLDB: %s", vText.c_str() ) );
+
+ return WritePriv( vText, strPrefixed, vbSendToLog );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Write text data to stderr. The text data does not need to
+// include a carrage line return as this is added to the text. The function also
+// then passes the text data into the CMICmnLog logger.
+// Type: Method.
+// Args: vText - (R) Text data. May be prefixed with MI app's short name.
+// vTxtForLogFile - (R) Text data.
+// vbSendToLog - (R) True = Yes send to the Log file too, false = do not. (Dflt = true)
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStderr::WritePriv( const CMIUtilString & vText, const CMIUtilString & vTxtForLogFile, const bool vbSendToLog /* = true */ )
+{
+ if( vText.length() == 0 )
+ return MIstatus::failure;
+
+ bool bOk = MIstatus::success;
+ {
+ // Grab the stderr thread lock while we print
+ CMIUtilThreadLock _lock( m_mutex );
+
+ // Send this text to stderr
+ const MIuint status = ::fputs( vText.c_str(), stderr );
+ if( status == EOF )
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_STDERR_ERR_NOT_ALL_DATA_WRITTEN ), vText.c_str() ) );
+ SetErrorDescription( errMsg );
+ bOk = MIstatus::failure;
+ }
+ else
+ {
+ ::fprintf( stderr, "\n" );
+ ::fflush( stderr );
+ }
+
+ // Send this text to the log
+ if( bOk && vbSendToLog )
+ bOk &= m_pLog->WriteLog( vTxtForLogFile );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Lock the availability of the stream stderr. Other users of *this stream will
+// be stalled until it is available (Unlock()).
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStderr::Lock( void )
+{
+ m_mutex.Lock();
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release a previously locked stderr.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStderr::Unlock( void )
+{
+ m_mutex.Unlock();
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Take MI Driver text message and send to the stderr stream. Also output to the
+// MI Log file.
+// Type: Static method.
+// Args: vrTxt - (R) Text.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnStreamStderr::TextToStderr( const CMIUtilString & vrTxt )
+{
+ const bool bLock = CMICmnStreamStderr::Instance().Lock();
+ const bool bOk = bLock && CMICmnStreamStderr::Instance().Write( vrTxt );
+ bLock && CMICmnStreamStderr::Instance().Unlock();
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Take an LLDB message and send to the stderr stream. The message is not always
+// an error message. The user has typed a command in to the Eclipse console (by-
+// passing Eclipse) and this is the result message from LLDB back to the user.
+// Also output to the MI Log file.
+// Type: Static method.
+// Args: vrTxt - (R) Text.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnStreamStderr::LLDBMsgToConsole( const CMIUtilString & vrTxt )
+{
+ const bool bLock = CMICmnStreamStderr::Instance().Lock();
+ const bool bOk = bLock && CMICmnStreamStderr::Instance().WriteLLDBMsg( vrTxt );
+ bLock && CMICmnStreamStderr::Instance().Unlock();
+
+ return bOk;
+}
+
diff --git a/tools/lldb-mi/MICmnStreamStderr.h b/tools/lldb-mi/MICmnStreamStderr.h
new file mode 100644
index 000000000000..45a1cf3bfc70
--- /dev/null
+++ b/tools/lldb-mi/MICmnStreamStderr.h
@@ -0,0 +1,76 @@
+//===-- MICmnStreamStderr.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnStreamStderr.h
+//
+// Overview: CMICmnStreamStderr interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MIUtilString.h"
+#include "MICmnBase.h"
+#include "MIUtilSingletonBase.h"
+#include "MIUtilThreadBaseStd.h"
+
+//++ ============================================================================
+// Details: MI common code class. The MI driver requires this object.
+// CMICmnStreamStderr sets up and tears downs stderr for the driver.
+//
+// Singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 19/03/2014.
+// Changes: None.
+//--
+class CMICmnStreamStderr
+: public CMICmnBase
+, public MI::ISingleton< CMICmnStreamStderr >
+{
+ friend class MI::ISingleton< CMICmnStreamStderr >;
+
+// Statics:
+public:
+ static bool TextToStderr( const CMIUtilString & vrTxt );
+ static bool LLDBMsgToConsole( const CMIUtilString & vrTxt );
+
+ // Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+ //
+ bool Lock( void );
+ bool Unlock( void );
+ bool Write( const CMIUtilString & vText, const bool vbSendToLog = true );
+ bool WriteLLDBMsg( const CMIUtilString & vText, const bool vbSendToLog = true );
+
+// Methods:
+private:
+ /* ctor */ CMICmnStreamStderr( void );
+ /* ctor */ CMICmnStreamStderr( const CMICmnStreamStderr & );
+ void operator=( const CMICmnStreamStderr & );
+ //
+ bool WritePriv( const CMIUtilString & vText, const CMIUtilString & vTxtForLogFile, const bool vbSendToLog = true );
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnStreamStderr( void );
+
+// Attributes:
+private:
+ CMIUtilThreadMutex m_mutex; // Mutex object for sync during Write()
+};
diff --git a/tools/lldb-mi/MICmnStreamStdin.cpp b/tools/lldb-mi/MICmnStreamStdin.cpp
new file mode 100644
index 000000000000..ccd3544c40f9
--- /dev/null
+++ b/tools/lldb-mi/MICmnStreamStdin.cpp
@@ -0,0 +1,421 @@
+//===-- MIUtilStreamStdin.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilStreamStdin.cpp
+//
+// Overview: CMICmnStreamStdin implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnStreamStdin.h"
+#include "MICmnStreamStdout.h"
+#include "MICmnResources.h"
+#include "MICmnLog.h"
+#include "MICmnThreadMgrStd.h"
+#include "MIUtilSingletonHelper.h"
+#include "MIDriver.h"
+#if defined( _MSC_VER )
+#include "MIUtilSystemWindows.h"
+#include "MICmnStreamStdinWindows.h"
+#else
+#include "MICmnStreamStdinLinux.h"
+#endif // defined( _MSC_VER )
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnStreamStdin constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnStreamStdin::CMICmnStreamStdin( void )
+: m_constStrThisThreadname( "MI stdin thread" )
+, m_pVisitor( nullptr )
+, m_strPromptCurrent( "(gdb)" )
+, m_bKeyCtrlCHit( false )
+, m_bShowPrompt( false )
+, m_bRedrawPrompt( true )
+, m_pStdinReadHandler( nullptr )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnStreamStdin destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnStreamStdin::~CMICmnStreamStdin( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this Stdin stream.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdin::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Note initialisation order is important here as some resources depend on previous
+ MI::ModuleInit< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
+ MI::ModuleInit< CMICmnResources > ( IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg );
+ MI::ModuleInit< CMICmnThreadMgrStd >( IDS_MI_INIT_ERR_THREADMGR, bOk, errMsg );
+#ifdef _MSC_VER
+ MI::ModuleInit< CMICmnStreamStdinWindows >( IDS_MI_INIT_ERR_OS_STDIN_HANDLER, bOk, errMsg );
+ bOk = bOk && SetOSStdinHandler( CMICmnStreamStdinWindows::Instance() );
+#else
+ MI::ModuleInit< CMICmnStreamStdinLinux >( IDS_MI_INIT_ERR_OS_STDIN_HANDLER, bOk, errMsg );
+ bOk = bOk && SetOSStdinHandler( CMICmnStreamStdinLinux::Instance() );
+#endif // ( _MSC_VER )
+
+ // The OS specific stdin stream handler must be set before *this class initialises
+ if( bOk && m_pStdinReadHandler == nullptr )
+ {
+ CMIUtilString strInitError( CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_STREAMSTDIN_OSHANDLER ), errMsg.c_str() ) );
+ SetErrorDescription( strInitError );
+ return MIstatus::failure;
+ }
+
+ // Other resources required
+ if( bOk )
+ {
+ m_bKeyCtrlCHit = false; // Reset
+ }
+
+ m_bInitialized = bOk;
+
+ if( !bOk )
+ {
+ CMIUtilString strInitError( CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_STREAMSTDIN ), errMsg.c_str() ) );
+ SetErrorDescription( strInitError );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this Stdin stream.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdin::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = false;
+
+ ClrErrorDescription();
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ m_pVisitor = nullptr;
+ m_bKeyCtrlCHit = false;
+
+ // Note shutdown order is important here
+#ifndef _MSC_VER
+ MI::ModuleShutdown< CMICmnStreamStdinLinux >( IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER, bOk, errMsg );
+#else
+ MI::ModuleShutdown< CMICmnStreamStdinWindows >( IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER, bOk, errMsg );
+#endif // ( _MSC_VER )
+ MI::ModuleShutdown< CMICmnThreadMgrStd >( IDS_MI_SHTDWN_ERR_THREADMGR, bOk, errMsg );
+ MI::ModuleShutdown< CMICmnResources > ( IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg );
+ MI::ModuleShutdown< CMICmnLog > ( IDS_MI_SHTDWN_ERR_LOG , bOk, errMsg );
+
+ if( !bOk )
+ {
+ SetErrorDescriptionn( MIRSRC( IDE_MI_SHTDWN_ERR_STREAMSTDIN ), errMsg.c_str() );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Validate and set the text that forms the prompt on the command line.
+// Type: Method.
+// Args: vNewPrompt - (R) Text description.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdin::SetPrompt( const CMIUtilString & vNewPrompt )
+{
+ if( vNewPrompt.empty() )
+ {
+ const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_STDIN_ERR_INVALID_PROMPT), vNewPrompt.c_str() ) );
+ CMICmnStreamStdout::Instance().Write( msg );
+ return MIstatus::failure;
+ }
+
+ m_strPromptCurrent = vNewPrompt;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the command line prompt text currently being used.
+// Type: Method.
+// Args: None.
+// Return: const CMIUtilString & - Functional failed.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnStreamStdin::GetPrompt( void ) const
+{
+ return m_strPromptCurrent;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Wait on input from stream Stdin. On each line of input received it is
+// validated and providing there are no errors on the stream or the input
+// buffer is not exceeded the data is passed to the visitor.
+// Type: Method.
+// Args: vrVisitor - (W) A client deriver callback.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdin::SetVisitor( IStreamStdin & vrVisitor )
+{
+ m_pVisitor = &vrVisitor;
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set whether to display optional command line prompt. The prompt is output to
+// stdout. Disable it when this may interfere with the client reading stdout as
+// input and it tries to interpret the prompt text to.
+// Type: Method.
+// Args: vbYes - (R) True = Yes prompt is shown/output to the user (stdout), false = no prompt.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+void CMICmnStreamStdin::SetEnablePrompt( const bool vbYes )
+{
+ m_bShowPrompt = vbYes;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get whether to display optional command line prompt. The prompt is output to
+// stdout. Disable it when this may interfere with the client reading stdout as
+// input and it tries to interpret the prompt text to.
+// Type: Method.
+// Args: None.
+// Return: bool - True = Yes prompt is shown/output to the user (stdout), false = no prompt.
+// Throws: None.
+//--
+bool CMICmnStreamStdin::GetEnablePrompt( void ) const
+{
+ return m_bShowPrompt;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine if stdin has any characters present in its buffer.
+// Type: Method.
+// Args: vwbAvail - (W) True = There is chars available, false = nothing there.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdin::InputAvailable( bool & vwbAvail )
+{
+ return m_pStdinReadHandler->InputAvailable( vwbAvail );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The monitoring on new line data calls back to the visitor object registered
+// with *this stdin monitoring. The monitoring to stops when the visitor returns
+// true for bYesExit flag. Errors output to log file.
+// This function runs in the thread "MI stdin monitor".
+// Type: Method.
+// vrwbYesAlive - (W) False = yes exit stdin monitoring, true = continue monitor.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdin::MonitorStdin( bool & vrwbYesAlive )
+{
+ if( m_bShowPrompt )
+ {
+ CMICmnStreamStdout & rStdoutMan = CMICmnStreamStdout::Instance();
+ rStdoutMan.WriteMIResponse( m_strPromptCurrent.c_str() );
+ m_bRedrawPrompt = false;
+ }
+
+ // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
+ if( m_bKeyCtrlCHit )
+ {
+ CMIDriver & rMIDriver = CMIDriver::Instance();
+ rMIDriver.SetExitApplicationFlag( false );
+ if( rMIDriver.GetExitApplicationFlag() )
+ {
+ vrwbYesAlive = false;
+ return MIstatus::success;
+ }
+
+ // Reset - the MI Driver received SIGINT during a running debug programm session
+ m_bKeyCtrlCHit = false;
+ }
+
+#if MICONFIG_POLL_FOR_STD_IN
+ bool bAvail = true;
+ // Check if there is stdin available
+ if( InputAvailable( bAvail ) )
+ {
+ // Early exit when there is no input
+ if( !bAvail )
+ return MIstatus::success;
+ }
+ else
+ {
+ vrwbYesAlive = false;
+ CMIDriver::Instance().SetExitApplicationFlag( true );
+ return MIstatus::failure;
+ }
+#endif // MICONFIG_POLL_FOR_STD_IN
+
+ // Read a line from std input
+ CMIUtilString stdinErrMsg;
+ const MIchar * pText = ReadLine( stdinErrMsg );
+
+ // Did something go wrong
+ const bool bHaveError( !stdinErrMsg.empty() );
+ if( (pText == nullptr) || bHaveError )
+ {
+ if( bHaveError )
+ {
+ CMICmnStreamStdout::Instance().Write( stdinErrMsg );
+ }
+ return MIstatus::failure;
+ }
+
+ // We have text so send it off to the visitor
+ bool bOk = MIstatus::success;
+ if( m_pVisitor != nullptr )
+ {
+ bool bYesExit = false;
+ bOk = m_pVisitor->ReadLine( CMIUtilString( pText ), bYesExit );
+ m_bRedrawPrompt = true;
+ vrwbYesAlive = !bYesExit;
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Wait on new line of data from stdin stream (completed by '\n' or '\r').
+// Type: Method.
+// Args: vwErrMsg - (W) Empty string ok or error description.
+// Return: MIchar * - text buffer pointer or NULL on failure.
+// Throws: None.
+//--
+const MIchar * CMICmnStreamStdin::ReadLine( CMIUtilString & vwErrMsg )
+{
+ return m_pStdinReadHandler->ReadLine( vwErrMsg );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Inform *this stream that the user hit Control-C key to exit.
+// The function is normally called by the SIGINT signal in sigint_handler() to
+// simulate kill app from the client.
+// This function is called by a Kernel thread.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMICmnStreamStdin::SetCtrlCHit( void )
+{
+ CMIUtilThreadLock lock( m_mutex );
+ m_bKeyCtrlCHit = true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The main worker method for this thread.
+// Type: Overridden.
+// Args: vrbIsAlive = (W) True = *this thread is working, false = thread has exited.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdin::ThreadRun( bool & vrbIsAlive )
+{
+ return MonitorStdin( vrbIsAlive );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Let this thread clean up after itself.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdin::ThreadFinish( void )
+{
+ // Do nothing - override to implement
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve *this thread object's name.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString & - Text.
+// Throws: None.
+//--
+const CMIUtilString & CMICmnStreamStdin::ThreadGetName( void ) const
+{
+ return m_constStrThisThreadname;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Mandatory set the OS specific stream stdin handler. *this class utilises the
+// handler to read data from the stdin stream and put into a queue for the
+// driver to read when able.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdin::SetOSStdinHandler( IOSStdinHandler & vrHandler )
+{
+ m_pStdinReadHandler = &vrHandler;
+
+ return MIstatus::success;
+}
diff --git a/tools/lldb-mi/MICmnStreamStdin.h b/tools/lldb-mi/MICmnStreamStdin.h
new file mode 100644
index 000000000000..edd79f60b8d4
--- /dev/null
+++ b/tools/lldb-mi/MICmnStreamStdin.h
@@ -0,0 +1,125 @@
+//===-- MIUtilStreamStdin.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilStreamStdin.h
+//
+// Overview: CMICmnStreamStdin interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MIUtilString.h"
+#include "MIUtilThreadBaseStd.h"
+#include "MICmnBase.h"
+#include "MIUtilSingletonBase.h"
+
+//++ ============================================================================
+// Details: MI common code class. Used to handle stream data from Stdin.
+// Singleton class using the Visitor pattern. A driver using the interface
+// provide can receive callbacks when a new line of data is received.
+// Each line is determined by a carriage return.
+// A singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 10/02/2014.
+// Changes: Factored out OS specific handling of reading stdin - IOR 16/06/2014.
+//--
+class CMICmnStreamStdin
+: public CMICmnBase
+, public CMIUtilThreadActiveObjBase
+, public MI::ISingleton< CMICmnStreamStdin >
+{
+ // Give singleton access to private constructors
+ friend MI::ISingleton< CMICmnStreamStdin >;
+
+// Class:
+public:
+ //++
+ // Description: Visitor pattern. Driver(s) use this interface to get a callback
+ // on each new line of data received from stdin.
+ //--
+ class IStreamStdin
+ {
+ public:
+ virtual bool ReadLine( const CMIUtilString & vStdInBuffer, bool & vrwbYesExit ) = 0;
+
+ /* dtor */ virtual ~IStreamStdin( void ) {};
+ };
+
+ //++
+ // Description: Specific OS stdin handling implementations are created and used by *this
+ // class. Seperates out functionality and enables handler to be set
+ // dynamically depended on the OS detected.
+ //--
+ class IOSStdinHandler
+ {
+ public:
+ virtual bool InputAvailable( bool & vwbAvail ) = 0;
+ virtual const MIchar * ReadLine( CMIUtilString & vwErrMsg ) = 0;
+
+ /* dtor */ virtual ~IOSStdinHandler( void ) {};
+ };
+
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+ //
+ const CMIUtilString & GetPrompt( void ) const;
+ bool SetPrompt( const CMIUtilString & vNewPrompt );
+ void SetEnablePrompt( const bool vbYes );
+ bool GetEnablePrompt( void ) const;
+ void SetCtrlCHit( void );
+ bool SetVisitor( IStreamStdin & vrVisitor );
+ bool SetOSStdinHandler( IOSStdinHandler & vrHandler );
+
+// Overridden:
+public:
+ // From CMIUtilThreadActiveObjBase
+ virtual const CMIUtilString & ThreadGetName( void ) const;
+
+// Overridden:
+protected:
+ // From CMIUtilThreadActiveObjBase
+ virtual bool ThreadRun( bool & vrIsAlive );
+ virtual bool ThreadFinish( void ); // Let this thread clean up after itself
+
+// Methods:
+private:
+ /* ctor */ CMICmnStreamStdin( void );
+ /* ctor */ CMICmnStreamStdin( const CMICmnStreamStdin & );
+ void operator=( const CMICmnStreamStdin & );
+
+ bool MonitorStdin( bool & vrwbYesExit );
+ const MIchar * ReadLine( CMIUtilString & vwErrMsg );
+ bool InputAvailable( bool & vbAvail ); // Bytes are available on stdin
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnStreamStdin( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_constStrThisThreadname;
+ IStreamStdin * m_pVisitor;
+ CMIUtilString m_strPromptCurrent; // Command line prompt as shown to the user
+ volatile bool m_bKeyCtrlCHit; // True = User hit Ctrl-C, false = has not yet
+ bool m_bShowPrompt; // True = Yes prompt is shown/output to the user (stdout), false = no prompt
+ bool m_bRedrawPrompt; // True = Prompt needs to be redrawn
+ IOSStdinHandler * m_pStdinReadHandler;
+};
+
diff --git a/tools/lldb-mi/MICmnStreamStdinLinux.cpp b/tools/lldb-mi/MICmnStreamStdinLinux.cpp
new file mode 100644
index 000000000000..f73dc32d8258
--- /dev/null
+++ b/tools/lldb-mi/MICmnStreamStdinLinux.cpp
@@ -0,0 +1,212 @@
+//===-- MICmnStreamStdinLinux.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilStreamStdin.cpp
+//
+// Overview: CMICmnStreamStdinLinux implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third Party Headers:
+#if !defined( _MSC_VER )
+#include <sys/select.h>
+#include <termios.h>
+#endif // !defined( _MSC_VER )
+#include <string.h> // For std::strerror()
+
+// In-house headers:
+#include "MICmnStreamStdinLinux.h"
+#include "MICmnLog.h"
+#include "MICmnResources.h"
+#include "MIUtilSingletonHelper.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnStreamStdinLinux constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnStreamStdinLinux::CMICmnStreamStdinLinux( void )
+: m_constBufferSize( 1024 )
+, m_pStdin( nullptr )
+, m_pCmdBuffer( nullptr )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnStreamStdinLinux destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnStreamStdinLinux::~CMICmnStreamStdinLinux( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this Stdin stream.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdinLinux::Initialize( void )
+{
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Note initialisation order is important here as some resources depend on previous
+ MI::ModuleInit< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
+ MI::ModuleInit< CMICmnResources >( IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg );
+
+ // Other resources required
+ if( bOk )
+ {
+ m_pCmdBuffer = new MIchar[ m_constBufferSize ];
+ m_pStdin = stdin;
+ }
+
+ // Clear error indicators for std input
+ ::clearerr( stdin );
+
+ m_bInitialized = bOk;
+
+ if( !bOk )
+ {
+ CMIUtilString strInitError( CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_OS_STDIN_HANDLER ), errMsg.c_str() ) );
+ SetErrorDescription( strInitError );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this Stdin stream.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdinLinux::Shutdown( void )
+{
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = false;
+
+ ClrErrorDescription();
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Tidy up
+ if( m_pCmdBuffer != nullptr )
+ {
+ delete [] m_pCmdBuffer;
+ m_pCmdBuffer = nullptr;
+ }
+ m_pStdin = nullptr;
+
+ // Note shutdown order is important here
+ MI::ModuleShutdown< CMICmnResources >( IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg );
+ MI::ModuleShutdown< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
+
+ if( !bOk )
+ {
+ SetErrorDescriptionn( MIRSRC( IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER ), errMsg.c_str() );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine if stdin has any characters present in its buffer.
+// Type: Method.
+// Args: vwbAvail - (W) True = There is chars available, false = nothing there.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdinLinux::InputAvailable( bool & vwbAvail )
+{
+/* AD: Not used ATM but could come in handy just in case we need to do
+ this, poll for input
+
+ static const int STDIN = 0;
+ static bool bInitialized = false;
+
+ if( !bInitialized )
+ {
+ // Use termios to turn off line buffering
+ ::termios term;
+ ::tcgetattr( STDIN, &term );
+ ::term.c_lflag &= ~ICANON;
+ ::tcsetattr( STDIN, TCSANOW, &term );
+ ::setbuf( stdin, NULL );
+ bInitialized = true;
+ }
+
+ int nBytesWaiting;
+ ::ioctl( STDIN, FIONREAD, &nBytesWaiting );
+ vwbAvail = (nBytesWaiting > 0);
+
+ return MIstatus::success;
+*/
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Wait on new line of data from stdin stream (completed by '\n' or '\r').
+// Type: Method.
+// Args: vwErrMsg - (W) Empty string ok or error description.
+// Return: MIchar * - text buffer pointer or NULL on failure.
+// Throws: None.
+//--
+const MIchar * CMICmnStreamStdinLinux::ReadLine( CMIUtilString & vwErrMsg )
+{
+ vwErrMsg.clear();
+
+ // Read user input
+ const MIchar * pText = ::fgets( &m_pCmdBuffer[ 0 ], m_constBufferSize, stdin );
+ if( pText == nullptr )
+ {
+ if( ::ferror( m_pStdin ) != 0 )
+ vwErrMsg = ::strerror( errno );
+ return nullptr;
+ }
+
+ // Strip off new line characters
+ for( MIchar * pI = m_pCmdBuffer; *pI != '\0'; pI++ )
+ {
+ if( (*pI == '\n') || (*pI == '\r') )
+ {
+ *pI = '\0';
+ break;
+ }
+ }
+
+ return pText;
+}
+
diff --git a/tools/lldb-mi/MICmnStreamStdinLinux.h b/tools/lldb-mi/MICmnStreamStdinLinux.h
new file mode 100644
index 000000000000..78d796634b34
--- /dev/null
+++ b/tools/lldb-mi/MICmnStreamStdinLinux.h
@@ -0,0 +1,75 @@
+//===-- MICmnStreamStdinWindows.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilStreamStdin.h
+//
+// Overview: CMICmnStreamStdinLinux interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MICmnStreamStdin.h"
+#include "MIUtilSingletonBase.h"
+
+//++ ============================================================================
+// Details: MI common code class. Specific OS stdin handling implementation.
+// CMICmnStreamStdin instance is set with stdin handler before using the
+// the stream. An instance of this class must be set up and ready to give
+// to the CMICmnStreamStdin before it initialises other CMICmnStreamStdin
+// will give an error.
+// Gotchas: None.
+// Authors: Illya Rudkin 16/06/2014.
+// Changes: None.
+//--
+class CMICmnStreamStdinLinux
+: public CMICmnBase
+, public CMICmnStreamStdin::IOSStdinHandler
+, public MI::ISingleton< CMICmnStreamStdinLinux >
+{
+ // Give singleton access to private constructors
+ friend MI::ISingleton< CMICmnStreamStdinLinux >;
+
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+
+// Overridden:
+public:
+ // From CMICmnStreamStdin::IOSpecificReadStreamStdin
+ virtual bool InputAvailable( bool & vwbAvail );
+ virtual const MIchar * ReadLine( CMIUtilString & vwErrMsg );
+
+// Methods:
+private:
+ /* ctor */ CMICmnStreamStdinLinux( void );
+ /* ctor */ CMICmnStreamStdinLinux( const CMICmnStreamStdin & );
+ void operator=( const CMICmnStreamStdin & );
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnStreamStdinLinux( void );
+
+// Attributes:
+private:
+ const MIuint m_constBufferSize;
+ FILE * m_pStdin;
+ MIchar * m_pCmdBuffer;
+};
+
diff --git a/tools/lldb-mi/MICmnStreamStdinWindows.cpp b/tools/lldb-mi/MICmnStreamStdinWindows.cpp
new file mode 100644
index 000000000000..2b24df8d61a6
--- /dev/null
+++ b/tools/lldb-mi/MICmnStreamStdinWindows.cpp
@@ -0,0 +1,279 @@
+//===-- MICmnStreamStdinWindows.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilStreamStdin.cpp
+//
+// Overview: CMICmnStreamStdinWindows implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third Party Headers:
+#if defined( _MSC_VER )
+#include <stdio.h>
+#include <Windows.h>
+#include <io.h>
+#include <conio.h>
+#endif // defined( _MSC_VER )
+#include <string.h>
+
+// In-house headers:
+#include "MICmnStreamStdinWindows.h"
+#include "MICmnLog.h"
+#include "MICmnResources.h"
+#include "MIUtilSystemWindows.h"
+#include "MIUtilSingletonHelper.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnStreamStdinWindows constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnStreamStdinWindows::CMICmnStreamStdinWindows( void )
+: m_constBufferSize( 1024 )
+, m_pStdin( nullptr )
+, m_pCmdBuffer( nullptr )
+, m_pStdinBuffer( nullptr )
+, m_nBytesToBeRead( 0 )
+, m_bRunningInConsoleWin( false )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnStreamStdinWindows destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnStreamStdinWindows::~CMICmnStreamStdinWindows( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this Stdin stream.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdinWindows::Initialize( void )
+{
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Note initialisation order is important here as some resources depend on previous
+ MI::ModuleInit< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
+ MI::ModuleInit< CMICmnResources >( IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg );
+
+ // Other resources required
+ if( bOk )
+ {
+ m_pCmdBuffer = new MIchar[ m_constBufferSize ];
+ m_pStdin = stdin;
+
+#if MICONFIG_CREATE_OWN_STDIN_BUFFER
+ // Give stdinput a user defined buffer
+ m_pStdinBuffer = new char[ 1024 ];
+ ::setbuf( stdin, m_pStdinBuffer );
+#endif // MICONFIG_CREATE_OWN_STDIN_BUFFER
+
+ // Clear error indicators for std input
+ ::clearerr( stdin );
+
+#if defined( _MSC_VER )
+ m_bRunningInConsoleWin = ::_isatty( ::fileno( stdin ) );
+#endif // #if defined( _MSC_VER )
+ }
+
+ m_bInitialized = bOk;
+
+ if( !bOk )
+ {
+ CMIUtilString strInitError( CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_OS_STDIN_HANDLER ), errMsg.c_str() ) );
+ SetErrorDescription( strInitError );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this Stdin stream.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdinWindows::Shutdown( void )
+{
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = false;
+
+ ClrErrorDescription();
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Tidy up
+ if( m_pCmdBuffer != nullptr )
+ {
+ delete [] m_pCmdBuffer;
+ m_pCmdBuffer = nullptr;
+ }
+ m_pStdin = nullptr;
+
+#if MICONFIG_CREATE_OWN_STDIN_BUFFER
+ if ( m_pStdinBuffer )
+ delete [] m_pStdinBuffer;
+ m_pStdinBuffer = nullptr;
+#endif // MICONFIG_CREATE_OWN_STDIN_BUFFER
+
+ // Note shutdown order is important here
+ MI::ModuleShutdown< CMICmnResources >( IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg );
+ MI::ModuleShutdown< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
+
+ if( !bOk )
+ {
+ SetErrorDescriptionn( MIRSRC( IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER ), errMsg.c_str() );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine if stdin has any characters present in its buffer.
+// Type: Method.
+// Args: vwbAvail - (W) True = There is chars available, false = nothing there.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdinWindows::InputAvailable( bool & vwbAvail )
+{
+ return m_bRunningInConsoleWin ? InputAvailableConsoleWin( vwbAvail ) : InputAvailableApplication( vwbAvail );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine if stdin has any characters present in its buffer. If running in a
+// terminal use _kbhit().
+// Type: Method.
+// Args: vwbAvail - (W) True = There is chars available, false = nothing there.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdinWindows::InputAvailableConsoleWin( bool & vwbAvail )
+{
+#if defined( _MSC_VER )
+ if( m_nBytesToBeRead == 0 )
+ {
+ // Get a windows handle to std input stream
+ HANDLE handle = ::GetStdHandle( STD_INPUT_HANDLE );
+ DWORD nBytesWaiting = ::_kbhit();
+
+ // Save the number of bytes to be read so that we can check if input is available to be read
+ m_nBytesToBeRead = nBytesWaiting;
+
+ // Return state of whether bytes are waiting or not
+ vwbAvail = (nBytesWaiting > 0);
+ }
+#endif // #if defined( _MSC_VER )
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine if stdin has any characters present in its buffer.
+// Type: Method.
+// Args: vwbAvail - (W) True = There is chars available, false = nothing there.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdinWindows::InputAvailableApplication( bool & vwbAvail )
+{
+ #if defined( _MSC_VER )
+ if( m_nBytesToBeRead == 0 )
+ {
+ // Get a windows handle to std input stream
+ HANDLE handle = ::GetStdHandle( STD_INPUT_HANDLE );
+ DWORD nBytesWaiting = 0;
+
+ // Ask how many bytes are available
+ if( ::PeekNamedPipe( handle, nullptr, 0, nullptr, &nBytesWaiting, nullptr ) == FALSE )
+ {
+ // This can occur when the client i.e. Eclipse closes the stdin stream 'cause it deems its work is finished
+ // for that debug session. May be we should be handling SIGKILL somehow?
+ const CMIUtilString osErrMsg( CMIUtilSystemWindows().GetOSLastError().StripCRAll() );
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_STDIN_ERR_CHKING_BYTE_AVAILABLE ), osErrMsg.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ // Save the number of bytes to be read so that we can check if input is available to be read
+ m_nBytesToBeRead = nBytesWaiting;
+
+ // Return state of whether bytes are waiting or not
+ vwbAvail = (nBytesWaiting > 0);
+ }
+#endif // #if defined( _MSC_VER )
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Wait on new line of data from stdin stream (completed by '\n' or '\r').
+// Type: Method.
+// Args: vwErrMsg - (W) Empty string ok or error description.
+// Return: MIchar * - text buffer pointer or NULL on failure.
+// Throws: None.
+//--
+const MIchar * CMICmnStreamStdinWindows::ReadLine( CMIUtilString & vwErrMsg )
+{
+ vwErrMsg.clear();
+
+ // Read user input
+ const MIchar * pText = ::fgets( &m_pCmdBuffer[ 0 ], m_constBufferSize, stdin );
+ if( pText == nullptr )
+ {
+ if( ::ferror( m_pStdin ) != 0 )
+ vwErrMsg = ::strerror( errno );
+ return nullptr;
+ }
+
+ // Subtract the number of bytes read so that we can check if input is available to be read
+ m_nBytesToBeRead = m_nBytesToBeRead - ::strlen( pText );
+
+ // Strip off new line characters
+ for( MIchar * pI = m_pCmdBuffer; *pI != '\0'; pI++ )
+ {
+ if( (*pI == '\n') || (*pI == '\r') )
+ {
+ *pI = '\0';
+ break;
+ }
+ }
+
+ return pText;
+} \ No newline at end of file
diff --git a/tools/lldb-mi/MICmnStreamStdinWindows.h b/tools/lldb-mi/MICmnStreamStdinWindows.h
new file mode 100644
index 000000000000..8feff8babfbf
--- /dev/null
+++ b/tools/lldb-mi/MICmnStreamStdinWindows.h
@@ -0,0 +1,81 @@
+//===-- MICmnStreamStdinWindows.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilStreamStdin.h
+//
+// Overview: CMICmnStreamStdinWindows interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MICmnStreamStdin.h"
+#include "MIUtilSingletonBase.h"
+
+//++ ============================================================================
+// Details: MI common code class. Specific OS stdin handling implementation.
+// CMICmnStreamStdin instance is set with stdin handler before using the
+// the stream. An instance of this class must be set up and ready to give
+// to the CMICmnStreamStdin before it initialises other CMICmnStreamStdin
+// will give an error.
+// Gotchas: None.
+// Authors: Illya Rudkin 16/06/2014.
+// Changes: None.
+//--
+class CMICmnStreamStdinWindows
+: public CMICmnBase
+, public CMICmnStreamStdin::IOSStdinHandler
+, public MI::ISingleton< CMICmnStreamStdinWindows >
+{
+ // Give singleton access to private constructors
+ friend MI::ISingleton< CMICmnStreamStdinWindows >;
+
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+
+// Overridden:
+public:
+ // From CMICmnStreamStdin::IOSpecificReadStreamStdin
+ virtual bool InputAvailable( bool & vwbAvail );
+ virtual const MIchar * ReadLine( CMIUtilString & vwErrMsg );
+
+// Methods:
+private:
+ /* ctor */ CMICmnStreamStdinWindows( void );
+ /* ctor */ CMICmnStreamStdinWindows( const CMICmnStreamStdinWindows & );
+ void operator=( const CMICmnStreamStdinWindows & );
+ //
+ bool InputAvailableConsoleWin( bool & vwbAvail );
+ bool InputAvailableApplication( bool & vwbAvail );
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnStreamStdinWindows( void );
+
+// Attributes:
+private:
+ const MIuint m_constBufferSize;
+ FILE * m_pStdin;
+ MIchar * m_pCmdBuffer;
+ MIchar * m_pStdinBuffer; // Custom buffer to store std input
+ MIuint m_nBytesToBeRead; // Checks that ::fgets() is holding on to data while ::PeekNamedPipe() returns nothing which causes a problem
+ bool m_bRunningInConsoleWin; // True = The application is being run in a Windows command line prompt window, false = by other means
+};
+
diff --git a/tools/lldb-mi/MICmnStreamStdout.cpp b/tools/lldb-mi/MICmnStreamStdout.cpp
new file mode 100644
index 000000000000..0532820eb790
--- /dev/null
+++ b/tools/lldb-mi/MICmnStreamStdout.cpp
@@ -0,0 +1,230 @@
+//===-- MIUtilStreamStdout.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilStreamcStdout.cpp
+//
+// Overview: CMICmnStreamStdout implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnStreamStdout.h"
+#include "MICmnLog.h"
+#include "MICmnResources.h"
+#include "MIDriver.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnStreamStdout constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnStreamStdout::CMICmnStreamStdout( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnStreamStdout destructor.
+// Type: Overridable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnStreamStdout::~CMICmnStreamStdout( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize resources for *this Stdout stream.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdout::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+
+#ifdef _MSC_VER
+ // Debugging / I/O issues with client.
+ // This is only required on Windows if you do not use ::flush(stdout). MI uses
+ // ::flush(stdout)
+ // It trys to ensure the process attached to the stdout steam gets ALL the data.
+ //::setbuf( stdout, NULL );
+#endif // _MSC_VER
+
+ m_bInitialized = bOk;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this Stdout stream.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdout::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ ClrErrorDescription();
+
+ m_bInitialized = false;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Write an MI format type response to stdout. The text data does not need to
+// include a carrage line return as this is added to the text. The function also
+// then passes the text data into the CMICmnLog logger.
+// Type: Method.
+// Args: vText - (R) MI formatted text.
+// vbSendToLog - (R) True = Yes send to the Log file too, false = do not. (Dflt = true)
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdout::WriteMIResponse( const CMIUtilString & vText, const bool vbSendToLog /* = true */ )
+{
+ return WritePriv( vText, vText, vbSendToLog );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Write text data to stdout. The text data does not need to
+// include a carrage line return as this is added to the text. The function also
+// then passes the text data into the CMICmnLog logger.
+// Type: Method.
+// Args: vText - (R) Text data.
+// vbSendToLog - (R) True = Yes send to the Log file too, false = do not. (Dflt = true)
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdout::Write( const CMIUtilString & vText, const bool vbSendToLog /* = true */ )
+{
+ if( vText.length() == 0 )
+ return MIstatus::failure;
+
+ const CMIUtilString strPrefixed( CMIUtilString::Format( "%s: %s", CMIDriver::Instance().GetAppNameShort().c_str(), vText.c_str() ) );
+
+ return WritePriv( strPrefixed, vText, vbSendToLog );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Write text data to stdout. The text data does not need to
+// include a carrage line return as this is added to the text. The function also
+// then passes the text data into the CMICmnLog logger.
+// Type: Method.
+// Args: vText - (R) Text data prefixed with MI app's short name.
+// vTxtForLogFile - (R) Text data.
+// vbSendToLog - (R) True = Yes send to the Log file too, false = do not. (Dflt = true)
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdout::WritePriv( const CMIUtilString & vText, const CMIUtilString & vTxtForLogFile, const bool vbSendToLog /* = true */ )
+{
+ if( vText.length() == 0 )
+ return MIstatus::failure;
+
+ bool bOk = MIstatus::success;
+ {
+ // Grab the stdout thread lock while we print
+ CMIUtilThreadLock _lock( m_mutex );
+
+ // Send this text to stdout
+ const MIuint status = ::fputs( vText.c_str(), stdout );
+ if( status == EOF )
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_STDOUT_ERR_NOT_ALL_DATA_WRITTEN ), vText.c_str() ) );
+ SetErrorDescription( errMsg );
+ bOk = MIstatus::failure;
+ }
+ else
+ {
+ ::fprintf( stdout, "\n" );
+ ::fflush( stdout );
+ }
+
+ // Send this text to the log
+ if( bOk && vbSendToLog )
+ bOk &= m_pLog->WriteLog( vTxtForLogFile );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Lock the availability of the stream stdout. Other users of *this stream will
+// be stalled until it is available (Unlock()).
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdout::Lock( void )
+{
+ m_mutex.Lock();
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release a previously locked stdout.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdout::Unlock( void )
+{
+ m_mutex.Unlock();
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Take a text data and send to the stdout stream. Also output to the MI Log
+// file.
+// Type: Static method.
+// Args: vrTxt - (R) Text.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMICmnStreamStdout::TextToStdout( const CMIUtilString & vrTxt )
+{
+ const bool bLock = CMICmnStreamStdout::Instance().Lock();
+ const bool bOk = bLock && CMICmnStreamStdout::Instance().WriteMIResponse( vrTxt );
+ bLock && CMICmnStreamStdout::Instance().Unlock();
+
+ return bOk;
+}
diff --git a/tools/lldb-mi/MICmnStreamStdout.h b/tools/lldb-mi/MICmnStreamStdout.h
new file mode 100644
index 000000000000..90f50478f06d
--- /dev/null
+++ b/tools/lldb-mi/MICmnStreamStdout.h
@@ -0,0 +1,75 @@
+//===-- MICmnStreamStdout.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnStreamStdout.h
+//
+// Overview: CMICmnStreamStdout interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MIUtilString.h"
+#include "MICmnBase.h"
+#include "MIUtilThreadBaseStd.h"
+#include "MIUtilSingletonBase.h"
+
+//++ ============================================================================
+// Details: MI common code class. The MI driver requires this object.
+// CMICmnStreamStdout sets up and tears downs stdout for the driver.
+//
+// Singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 12/02/2014.
+// Changes: None.
+//--
+class CMICmnStreamStdout
+: public CMICmnBase
+, public MI::ISingleton< CMICmnStreamStdout >
+{
+ friend class MI::ISingleton< CMICmnStreamStdout >;
+
+// Statics:
+public:
+ static bool TextToStdout( const CMIUtilString & vrTxt );
+
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+ //
+ bool Lock( void );
+ bool Unlock( void );
+ bool Write( const CMIUtilString & vText, const bool vbSendToLog = true );
+ bool WriteMIResponse( const CMIUtilString & vText, const bool vbSendToLog = true );
+
+// Methods:
+private:
+ /* ctor */ CMICmnStreamStdout( void );
+ /* ctor */ CMICmnStreamStdout( const CMICmnStreamStdout & );
+ void operator=( const CMICmnStreamStdout & );
+ //
+ bool WritePriv( const CMIUtilString & vText, const CMIUtilString & vTxtForLogFile, const bool vbSendToLog = true );
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnStreamStdout( void );
+
+// Attributes:
+private:
+ CMIUtilThreadMutex m_mutex; // Mutex object for sync during writing to stream
+};
diff --git a/tools/lldb-mi/MICmnThreadMgrStd.cpp b/tools/lldb-mi/MICmnThreadMgrStd.cpp
new file mode 100644
index 000000000000..757012a697e0
--- /dev/null
+++ b/tools/lldb-mi/MICmnThreadMgrStd.cpp
@@ -0,0 +1,167 @@
+//===-- MICmnThreadMgr.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnThreadMgr.cpp
+//
+// Overview: CMICmnThreadMgr implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MICmnThreadMgrStd.h"
+#include "MICmnLog.h"
+#include "MICmnResources.h"
+#include "MIUtilSingletonHelper.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnThreadMgr constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnThreadMgrStd::CMICmnThreadMgrStd( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMICmnThreadMgr destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMICmnThreadMgrStd::~CMICmnThreadMgrStd( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialise resources for *this thread manager.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnThreadMgrStd::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+
+ ClrErrorDescription();
+ CMIUtilString errMsg;
+
+ // Note initialisation order is important here as some resources depend on previous
+ MI::ModuleInit< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
+ MI::ModuleInit< CMICmnResources >( IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg );
+
+ m_bInitialized = bOk;
+
+ if( !bOk )
+ {
+ CMIUtilString strInitError( CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_THREADMGR ), errMsg.c_str() ) );
+ SetErrorDescription( strInitError );
+ return MIstatus::failure;
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resources for *this thread manager.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnThreadMgrStd::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ m_bInitialized = false;
+
+ ClrErrorDescription();
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Tidy up
+ ThreadAllTerminate();
+
+ // Note shutdown order is important here
+ MI::ModuleShutdown< CMICmnResources >( IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg );
+ MI::ModuleShutdown< CMICmnLog > ( IDS_MI_SHTDWN_ERR_LOG , bOk, errMsg );
+
+ if( !bOk )
+ {
+ SetErrorDescriptionn( MIRSRC( IDS_MI_SHUTDOWN_ERR ), errMsg.c_str() );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Ask the thread manager to kill all threads and wait until they have died
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnThreadMgrStd::ThreadAllTerminate( void )
+{
+ ThreadList_t::const_iterator it = m_threadList.begin();
+ for( ; it != m_threadList.end(); ++it )
+ {
+ // If the thread is still running
+ CMIUtilThreadActiveObjBase * pThread = *it;
+ if( pThread->ThreadIsActive() )
+ {
+ // Ask this thread to kill itself
+ pThread->ThreadKill();
+
+ // Wait for this thread to die
+ pThread->ThreadJoin();
+ }
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add a thread object to *this manager's list of thread objects. The list to
+// used to manage thread objects centrally.
+// Type: Method.
+// Args: vrObj - (R) A thread object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMICmnThreadMgrStd::AddThread( const CMIUtilThreadActiveObjBase & vrObj )
+{
+ m_threadList.push_back( const_cast< CMIUtilThreadActiveObjBase * >( &vrObj ) );
+
+ return MIstatus::success;
+}
diff --git a/tools/lldb-mi/MICmnThreadMgrStd.h b/tools/lldb-mi/MICmnThreadMgrStd.h
new file mode 100644
index 000000000000..f0c157a468af
--- /dev/null
+++ b/tools/lldb-mi/MICmnThreadMgrStd.h
@@ -0,0 +1,134 @@
+//===-- MICmnThreadMgrStd.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MICmnThreadMgrStd.h
+//
+// Overview: CMICmnThreadMgr interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <vector>
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MIUtilThreadBaseStd.h"
+#include "MICmnResources.h"
+#include "MIUtilSingletonBase.h"
+
+//++ ============================================================================
+// Details: MI's worker thread (active thread) manager.
+// The manager creates threads and behalf of clients. Client are
+// responsible for their threads and can delete them when necessary.
+// This manager will stop and delete all threads on *this manager's
+// shutdown.
+// Singleton class.
+// Gotchas: None.
+// Authors: Aidan Dodds 12/03/2014.
+// Changes: None.
+//--
+class CMICmnThreadMgrStd
+: public CMICmnBase
+, public MI::ISingleton< CMICmnThreadMgrStd >
+{
+ friend MI::ISingleton< CMICmnThreadMgrStd >;
+
+// Methods:
+public:
+ bool Initialize( void );
+ bool Shutdown( void );
+ bool ThreadAllTerminate( void ); // Ask all threads to stop (caution)
+ template< typename T > // Ask the thread manager to start and stop threads on our behalf
+ bool ThreadStart( T & vrwObject );
+
+// Typedef:
+private:
+ typedef std::vector< CMIUtilThreadActiveObjBase * > ThreadList_t;
+
+// Methods:
+private:
+ /* ctor */ CMICmnThreadMgrStd( void );
+ /* ctor */ CMICmnThreadMgrStd( const CMICmnThreadMgrStd & );
+ void operator=( const CMICmnThreadMgrStd & );
+ //
+ bool AddThread( const CMIUtilThreadActiveObjBase & vrObj ); // Add a thread for monitoring by the threadmanager
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMICmnThreadMgrStd( void );
+
+// Attributes:
+private:
+ CMIUtilThreadMutex m_mutex;
+ ThreadList_t m_threadList;
+};
+
+//++ ------------------------------------------------------------------------------------
+// Details: Given a thread object start its (worker) thread to do work. The object is
+// added to the *this manager for housekeeping and deletion of all thread objects.
+// Type: Template method.
+// Args: vrwThreadObj - (RW) A CMIUtilThreadActiveObjBase derived object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+template< typename T >
+bool CMICmnThreadMgrStd::ThreadStart( T & vrwThreadObj )
+{
+ bool bOk = MIstatus::success;
+
+ // Grab a reference to the base object type
+ CMIUtilThreadActiveObjBase & rObj = static_cast< CMIUtilThreadActiveObjBase & >( vrwThreadObj );
+
+ // Add to the thread managers internal database
+ bOk &= AddThread( rObj );
+ if( !bOk )
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ), vrwThreadObj.ThreadGetName().c_str() ) );
+ SetErrorDescription( errMsg );
+ return MIstatus::failure;
+ }
+
+ // Grab a reference on behalf of the caller
+ bOk &= vrwThreadObj.Acquire();
+ if( !bOk )
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ), vrwThreadObj.ThreadGetName().c_str() ) );
+ SetErrorDescription( errMsg );
+ return MIstatus::failure;
+ }
+
+ // Thread is already started
+ // This call must come after the reference count increment
+ if( vrwThreadObj.ThreadIsActive() )
+ {
+ // Early exit on thread already running condition
+ return MIstatus::success;
+ }
+
+ // Start the thread running
+ bOk &= vrwThreadObj.ThreadExecute();
+ if( !bOk )
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ), vrwThreadObj.ThreadGetName().c_str() ) );
+ SetErrorDescription( errMsg );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
diff --git a/tools/lldb-mi/MIDataTypes.h b/tools/lldb-mi/MIDataTypes.h
new file mode 100644
index 000000000000..c7980a8851a3
--- /dev/null
+++ b/tools/lldb-mi/MIDataTypes.h
@@ -0,0 +1,100 @@
+//===-- MIDataTypes.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIDataTypes.h
+//
+// Overview: Common global switches, macros, etc.
+//
+// This file contains common data types required by applications
+// generally. If supported by the compiler, this file should be
+// #include'd as part of the project's PCH (precompiled header).
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+//--------------------------------------------------------------------------------------
+// Windows headers:
+#ifdef _WIN32
+
+// Debugging:
+#ifdef _DEBUG
+#include <crtdbg.h> // C-runtime debugging library (defines _ASSERT).
+#endif // _DEBUG
+
+#endif // _WIN32
+
+//--------------------------------------------------------------------------------------
+// Common definitions:
+
+// Function return status
+namespace MIstatus
+{
+ const bool success = true;
+ const bool failure = false;
+}
+
+// Use to avoid "unused parameter" compiler warnings:
+#define MIunused( x ) (void) x;
+
+#ifdef _WIN32
+#define MI_NO_INITIALIZE_VTABLE __declspec( novtable )
+#define MI_FORCE_INLINE __forceinline
+#else
+#define MI_NO_INITIALIZE_VTABLE
+#define MI_FORCE_INLINE inline
+// __attribute__( ( always_inline ) )
+#endif // _WIN32
+
+// Portability issues
+#ifdef _WIN64
+ typedef unsigned __int64 size_t;
+ typedef unsigned __int64 PointerToInteger_t;
+ typedef __int64 MIint;
+ typedef unsigned __int64 MIuint;
+#else
+ #ifdef _WIN32
+ typedef unsigned int size_t;
+ typedef unsigned int PointerToInteger_t;
+ typedef int MIint;
+ typedef unsigned int MIuint;
+ #else
+// typedef long unsigned int size_t; // size_t already defined
+ typedef unsigned int PointerToInteger_t;
+ typedef int MIint;
+ typedef unsigned int MIuint;
+
+ #define MAX_PATH 4096
+ #endif // _WIN32
+#endif // _WIN64
+
+//--------------------------------------------------------------------------------------
+// Common types:
+
+// Fundamentals:
+typedef float MIflt;
+typedef double MIdbl;
+typedef char MIchar; // Defaults to signed char, i.e. MIschar.
+typedef signed char MIschar; // Range: -128 to 127. More explicit than using MIchar.
+typedef unsigned char MIuchar; // Range: 0 to 255.
+typedef long long MIint64; // 64bit signed integer.
+typedef unsigned long long MIuint64; // 64bit unsigned integer.
+
+//using namespace std; // Better to put this or std:: at translation units scope.
+
+//--------------------------------------------------------------------------------------
+// Common routines:
+
+//--------------------------------------------------------------------------------------
diff --git a/tools/lldb-mi/MIDriver.cpp b/tools/lldb-mi/MIDriver.cpp
new file mode 100644
index 000000000000..759d54a5364d
--- /dev/null
+++ b/tools/lldb-mi/MIDriver.cpp
@@ -0,0 +1,1276 @@
+//===-- MIDriver.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIDriver.cpp
+//
+// Overview: CMIDriver implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third party headers:
+#include <stdarg.h> // va_list, va_start, var_end
+#include <iostream>
+#include <lldb/API/SBError.h>
+
+// In-house headers:
+#include "Driver.h"
+#include "MIDriver.h"
+#include "MICmnResources.h"
+#include "MICmnLog.h"
+#include "MICmdMgr.h"
+#include "MICmnLLDBDebugger.h"
+#include "MICmnMIResultRecord.h"
+#include "MICmnMIValueConst.h"
+#include "MICmnThreadMgrStd.h"
+#include "MIUtilDebug.h"
+#include "MIUtilSingletonHelper.h"
+#include "MICmnStreamStdout.h"
+#include "MICmnStreamStderr.h"
+#include "MICmdArgValFile.h"
+#include "MICmdArgValString.h"
+#include "MICmnConfig.h"
+
+// Instantiations:
+#if _DEBUG
+ const CMIUtilString CMIDriver::ms_constMIVersion = MIRSRC( IDS_MI_VERSION_DESCRIPTION_DEBUG );
+#else
+ const CMIUtilString CMIDriver::ms_constMIVersion = MIRSRC( IDS_MI_VERSION_DESCRIPTION ); // Matches version in resources file
+#endif // _DEBUG
+const CMIUtilString CMIDriver::ms_constAppNameShort( MIRSRC( IDS_MI_APPNAME_SHORT ) );
+const CMIUtilString CMIDriver::ms_constAppNameLong( MIRSRC( IDS_MI_APPNAME_LONG ) );
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIDriver constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIDriver::CMIDriver( void )
+: m_bFallThruToOtherDriverEnabled( false )
+, m_bDriverIsExiting( false )
+, m_handleMainThread( 0 )
+, m_rStdin( CMICmnStreamStdin::Instance() )
+, m_rLldbDebugger( CMICmnLLDBDebugger::Instance() )
+, m_rStdOut( CMICmnStreamStdout::Instance() )
+, m_eCurrentDriverState( eDriverState_NotRunning )
+, m_bHaveExecutableFileNamePathOnCmdLine( false )
+, m_bDriverDebuggingArgExecutable( false )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIDriver destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIDriver::~CMIDriver( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set whether *this driver (the parent) is enabled to pass a command to its
+// fall through (child) driver to interpret the command and do work instead
+// (if *this driver decides it can't hanled the command).
+// Type: Method.
+// Args: vbYes - (R) True = yes fall through, false = do not pass on command.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::SetEnableFallThru( const bool vbYes )
+{
+ m_bFallThruToOtherDriverEnabled = vbYes;
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get whether *this driver (the parent) is enabled to pass a command to its
+// fall through (child) driver to interpret the command and do work instead
+// (if *this driver decides it can't hanled the command).
+// Type: Method.
+// Args: None.
+// Return: bool - True = yes fall through, false = do not pass on command.
+// Throws: None.
+//--
+bool CMIDriver::GetEnableFallThru( void ) const
+{
+ return m_bFallThruToOtherDriverEnabled;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve MI's application name of itself.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - Text description.
+// Throws: None.
+//--
+const CMIUtilString & CMIDriver::GetAppNameShort( void ) const
+{
+ return ms_constAppNameShort;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve MI's application name of itself.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - Text description.
+// Throws: None.
+//--
+const CMIUtilString & CMIDriver::GetAppNameLong( void ) const
+{
+ return ms_constAppNameLong;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve MI's version description of itself.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - Text description.
+// Throws: None.
+//--
+const CMIUtilString & CMIDriver::GetVersionDescription( void ) const
+{
+ return ms_constMIVersion;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize setup *this driver ready for use.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::Initialize( void )
+{
+ m_eCurrentDriverState = eDriverState_Initialising;
+ m_clientUsageRefCnt++;
+
+ ClrErrorDescription();
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Initialize all of the modules we depend on
+ MI::ModuleInit< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
+ MI::ModuleInit< CMICmnStreamStdout >( IDS_MI_INIT_ERR_STREAMSTDOUT , bOk, errMsg );
+ MI::ModuleInit< CMICmnStreamStderr >( IDS_MI_INIT_ERR_STREAMSTDERR , bOk, errMsg );
+ MI::ModuleInit< CMICmnResources > ( IDS_MI_INIT_ERR_RESOURCES , bOk, errMsg );
+ MI::ModuleInit< CMICmnThreadMgrStd >( IDS_MI_INIT_ERR_THREADMANAGER, bOk, errMsg );
+ MI::ModuleInit< CMICmnStreamStdin > ( IDS_MI_INIT_ERR_STREAMSTDIN , bOk, errMsg );
+ MI::ModuleInit< CMICmdMgr > ( IDS_MI_INIT_ERR_CMDMGR , bOk, errMsg );
+ bOk &= m_rLldbDebugger.SetDriver( *this );
+ MI::ModuleInit< CMICmnLLDBDebugger >( IDS_MI_INIT_ERR_LLDBDEBUGGER , bOk, errMsg );
+
+#if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
+ CMIDriverMgr & rDrvMgr = CMIDriverMgr::Instance();
+ bOk = bOk && rDrvMgr.RegisterDriver( *g_driver, "LLDB driver" ); // Will be pass thru driver
+ if( bOk )
+ {
+ bOk = SetEnableFallThru( false ); // This is intentional at this time - yet to be fully implemented
+ bOk = bOk && SetDriverToFallThruTo( *g_driver );
+ CMIUtilString strOtherDrvErrMsg;
+ if( bOk && GetEnableFallThru() && !g_driver->MISetup( strOtherDrvErrMsg ) )
+ {
+ bOk = false;
+ errMsg = CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_FALLTHRUDRIVER ), strOtherDrvErrMsg.c_str() );
+ }
+ }
+#endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
+
+ m_bExitApp = false;
+
+ m_bInitialized = bOk;
+
+ if( !bOk )
+ {
+ const CMIUtilString msg = CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_DRIVER ), errMsg.c_str() );
+ SetErrorDescription( msg );
+ return MIstatus::failure;
+ }
+
+ m_eCurrentDriverState = eDriverState_RunningNotDebugging;
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Unbind detach or release resources used by *this driver.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::Shutdown( void )
+{
+ if( --m_clientUsageRefCnt > 0 )
+ return MIstatus::success;
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ m_eCurrentDriverState = eDriverState_ShuttingDown;
+
+ ClrErrorDescription();
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Shutdown all of the modules we depend on
+ MI::ModuleShutdown< CMICmnLLDBDebugger >( IDS_MI_INIT_ERR_LLDBDEBUGGER , bOk, errMsg );
+ MI::ModuleShutdown< CMICmdMgr > ( IDS_MI_INIT_ERR_CMDMGR , bOk, errMsg );
+ MI::ModuleShutdown< CMICmnStreamStdin > ( IDS_MI_INIT_ERR_STREAMSTDIN , bOk, errMsg );
+ MI::ModuleShutdown< CMICmnThreadMgrStd >( IDS_MI_INIT_ERR_THREADMANAGER, bOk, errMsg );
+ MI::ModuleShutdown< CMICmnResources > ( IDS_MI_INIT_ERR_RESOURCES , bOk, errMsg );
+ MI::ModuleShutdown< CMICmnStreamStderr >( IDS_MI_INIT_ERR_STREAMSTDERR , bOk, errMsg );
+ MI::ModuleShutdown< CMICmnStreamStdout >( IDS_MI_INIT_ERR_STREAMSTDOUT , bOk, errMsg );
+ MI::ModuleShutdown< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
+
+ if( !bOk )
+ {
+ SetErrorDescriptionn( MIRSRC( IDS_MI_SHUTDOWN_ERR ), errMsg.c_str() );
+ }
+
+ m_eCurrentDriverState = eDriverState_NotRunning;
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Work function. Client (the driver's user) is able to append their own message
+// in to the MI's Log trace file.
+// Type: Method.
+// Args: vMessage - (R) Client's text message.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::WriteMessageToLog( const CMIUtilString & vMessage )
+{
+ CMIUtilString msg;
+ msg = CMIUtilString::Format( MIRSRC( IDS_MI_CLIENT_MSG ), vMessage.c_str() );
+ return m_pLog->Write( msg, CMICmnLog::eLogVerbosity_ClientMsg );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDriverMgr calls *this driver initialize setup ready for use.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::DoInitialize( void )
+{
+ return CMIDriver::Instance().Initialize();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDriverMgr calls *this driver to unbind detach or release resources used by
+// *this driver.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::DoShutdown( void )
+{
+ return CMIDriver::Instance().Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the name for *this driver.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString & - Driver name.
+// Throws: None.
+//--
+const CMIUtilString & CMIDriver::GetName( void ) const
+{
+ const CMIUtilString & rName = GetAppNameLong();
+ const CMIUtilString & rVsn = GetVersionDescription();
+ static CMIUtilString strName = CMIUtilString::Format( "%s %s", rName.c_str(), rVsn.c_str() );
+
+ return strName;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve *this driver's last error condition.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString - Text description.
+// Throws: None.
+//--
+CMIUtilString CMIDriver::GetError( void ) const
+{
+ return GetErrorDescription();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Call *this driver to resize the console window.
+// Type: Overridden.
+// Args: vTermWidth - (R) New window column size.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+void CMIDriver::DoResizeWindow( const uint32_t vTermWidth )
+{
+ GetTheDebugger().SetTerminalWidth( vTermWidth );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Call *this driver to return it's debugger.
+// Type: Overridden.
+// Args: None.
+// Return: lldb::SBDebugger & - LLDB debugger object reference.
+// Throws: None.
+//--
+lldb::SBDebugger & CMIDriver::GetTheDebugger( void )
+{
+ return m_rLldbDebugger.GetTheDebugger();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Specify another driver *this driver can call should this driver not be able
+// to handle the client data input. DoFallThruToAnotherDriver() makes the call.
+// Type: Overridden.
+// Args: vrOtherDriver - (R) Reference to another driver object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::SetDriverToFallThruTo( const CMIDriverBase & vrOtherDriver )
+{
+ m_pDriverFallThru = const_cast< CMIDriverBase * >( &vrOtherDriver );
+
+ return m_pDriverFallThru->SetDriverParent( *this );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Proxy function CMIDriverMgr IDriver interface implementation. *this driver's
+// implementation called from here to match the existing function name of the
+// original LLDb driver class (the extra indirection is not necessarily required).
+// Check the arguments that were passed to this program to make sure they are
+// valid and to get their argument values (if any).
+// Type: Overridden.
+// Args: argc - (R) An integer that contains the count of arguments that follow in
+// argv. The argc parameter is always greater than or equal to 1.
+// argv - (R) An array of null-terminated strings representing command-line
+// arguments entered by the user of the program. By convention,
+// argv[0] is the command with which the program is invoked.
+// vpStdOut - (R) Pointer to a standard output stream.
+// vwbExiting - (W) True = *this want to exit, Reasons: help, invalid arg(s),
+// version information only.
+// False = Continue to work, start debugger i.e. Command
+// interpreter.
+// Return: lldb::SBError - LLDB current error status.
+// Throws: None.
+//--
+lldb::SBError CMIDriver::DoParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting )
+{
+ return ParseArgs( argc, argv, vpStdOut, vwbExiting );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Check the arguments that were passed to this program to make sure they are
+// valid and to get their argument values (if any). The following are options
+// that are only handled by *this driver:
+// --executable
+// The application's options --interpreter and --executable in code act very similar.
+// The --executable is necessary to differentiate whither the MI Driver is being
+// using by a client i.e. Eclipse or from the command line. Eclipse issues the option
+// --interpreter and also passes additional arguments which can be interpreted as an
+// executable if called from the command line. Using --executable tells the MI
+// Driver is being called the command line and that the executable argument is indeed
+// a specified executable an so actions commands to set up the executable for a
+// debug session. Using --interpreter on the commnd line does not action additional
+// commands to initialise a debug session and so be able to launch the process.
+// Type: Overridden.
+// Args: argc - (R) An integer that contains the count of arguments that follow in
+// argv. The argc parameter is always greater than or equal to 1.
+// argv - (R) An array of null-terminated strings representing command-line
+// arguments entered by the user of the program. By convention,
+// argv[0] is the command with which the program is invoked.
+// vpStdOut - (R) Pointer to a standard output stream.
+// vwbExiting - (W) True = *this want to exit, Reasons: help, invalid arg(s),
+// version information only.
+// False = Continue to work, start debugger i.e. Command
+// interpreter.
+// Return: lldb::SBError - LLDB current error status.
+// Throws: None.
+//--
+lldb::SBError CMIDriver::ParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting )
+{
+ lldb::SBError errStatus;
+ const bool bHaveArgs( argc >= 2 );
+
+ // *** Add any args handled here to GetHelpOnCmdLineArgOptions() ***
+
+ // CODETAG_MIDRIVE_CMD_LINE_ARG_HANDLING
+ // Look for the command line options
+ bool bHaveExecutableFileNamePath = false;
+ bool bHaveExecutableLongOption = false;
+
+ if( bHaveArgs )
+ {
+ // Search right to left to look for the executable
+ for( MIint i = argc - 1; i > 0; i-- )
+ {
+ const CMIUtilString strArg( argv[ i ] );
+ const CMICmdArgValFile argFile;
+ if( argFile.IsFilePath( strArg ) ||
+ CMICmdArgValString( true, false, true ).IsStringArg( strArg ))
+ {
+ bHaveExecutableFileNamePath = true;
+ m_strCmdLineArgExecuteableFileNamePath = argFile.GetFileNamePath( strArg );
+ m_bHaveExecutableFileNamePathOnCmdLine = true;
+ }
+ // This argument is also check for in CMIDriverMgr::ParseArgs()
+ if( 0 == strArg.compare( "--executable" ) ) // Used to specify that there is executable argument also on the command line
+ { // See fn description.
+ bHaveExecutableLongOption = true;
+ }
+ }
+ }
+
+ if( bHaveExecutableFileNamePath && bHaveExecutableLongOption )
+ {
+ // CODETAG_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
+#if MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
+ SetDriverDebuggingArgExecutable();
+#else
+ vwbExiting = true;
+ errStatus.SetErrorString( MIRSRC( IDS_DRIVER_ERR_LOCAL_DEBUG_NOT_IMPL ) );
+#endif // MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
+ }
+
+ return errStatus;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: A client can ask if *this driver is GDB/MI compatible.
+// Type: Overridden.
+// Args: None.
+// Return: True - GBD/MI compatible LLDB front end.
+// False - Not GBD/MI compatible LLDB front end.
+// Throws: None.
+//--
+bool CMIDriver::GetDriverIsGDBMICompatibleDriver( void ) const
+{
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Callback function for monitoring stream stdin object. Part of the visitor
+// pattern.
+// This function is called by the CMICmnStreamStdin::CThreadStdin
+// "stdin monitor" thread (ID).
+// Type: Overridden.
+// Args: vStdInBuffer - (R) Copy of the current stdin line data.
+// vrbYesExit - (RW) True = yes exit stdin monitoring, false = continue monitor.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::ReadLine( const CMIUtilString & vStdInBuffer, bool & vrwbYesExit )
+{
+ // For debugging. Update prompt show stdin is working
+ //printf( "%s\n", vStdInBuffer.c_str() );
+ //fflush( stdout );
+
+ // Special case look for the quit command here so stop monitoring stdin stream
+ // So we do not go back to fgetc() and wait and hang thread on exit
+ if( vStdInBuffer == "quit" )
+ vrwbYesExit = true;
+
+ // 1. Put new line in the queue container by stdin monitor thread
+ // 2. Then *this driver calls ReadStdinLineQueue() when ready to read the queue in its
+ // own thread
+ const bool bOk = QueueMICommand( vStdInBuffer );
+
+ // Check to see if the *this driver is shutting down (exit application)
+ if( !vrwbYesExit )
+ vrwbYesExit = m_bDriverIsExiting;
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Start worker threads for the driver.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::StartWorkerThreads( void )
+{
+ bool bOk = MIstatus::success;
+
+ // Grab the thread manager
+ CMICmnThreadMgrStd & rThreadMgr = CMICmnThreadMgrStd::Instance();
+
+ // Start the stdin thread
+ bOk &= m_rStdin.SetVisitor( *this );
+ if( bOk && !rThreadMgr.ThreadStart< CMICmnStreamStdin >( m_rStdin ))
+ {
+ const CMIUtilString errMsg = CMIUtilString::Format( MIRSRC( IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ), CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str() );
+ SetErrorDescriptionn( errMsg );
+ return MIstatus::failure;
+ }
+
+ // Start the event polling thread
+ if( bOk && !rThreadMgr.ThreadStart< CMICmnLLDBDebugger >( m_rLldbDebugger ) )
+ {
+ const CMIUtilString errMsg = CMIUtilString::Format( MIRSRC( IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ), CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str() );
+ SetErrorDescriptionn( errMsg );
+ return MIstatus::failure;
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Stop worker threads for the driver.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::StopWorkerThreads( void )
+{
+ CMICmnThreadMgrStd & rThreadMgr = CMICmnThreadMgrStd::Instance();
+ return rThreadMgr.ThreadAllTerminate();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Call this function puts *this driver to work.
+// This function is used by the application's main thread.
+// Type: Overridden.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::DoMainLoop( void )
+{
+ if( !InitClientIDEToMIDriver() ) // Init Eclipse IDE
+ {
+ SetErrorDescriptionn( MIRSRC( IDS_MI_INIT_ERR_CLIENT_USING_DRIVER ) );
+ return MIstatus::failure;
+ }
+
+ if( !StartWorkerThreads() )
+ return MIstatus::failure;
+
+ // App is not quitting currently
+ m_bExitApp = false;
+
+ // CODETAG_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
+#if MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
+ if( HaveExecutableFileNamePathOnCmdLine() )
+ {
+ if( !LocalDebugSessionStartupInjectCommands() )
+ {
+ SetErrorDescription( MIRSRC( IDS_MI_INIT_ERR_LOCAL_DEBUG_SESSION ) );
+ return MIstatus::failure;
+ }
+ }
+#endif // MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION
+
+ // While the app is active
+ while( !m_bExitApp )
+ {
+ // Poll stdin queue and dispatch
+ if( !ReadStdinLineQueue() )
+ {
+ // Something went wrong
+ break;
+ }
+ }
+
+ // Signal that the application is shutting down
+ DoAppQuit();
+
+ // Close and wait for the workers to stop
+ StopWorkerThreads();
+
+ // Ensure that a new line is sent as the last act of the dying driver
+ m_rStdOut.WriteMIResponse( "\n", false );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: *this driver sits and waits for input to the stdin line queue shared by *this
+// driver and the stdin monitor thread, it queues, *this reads, interprets and
+// reacts.
+// This function is used by the application's main thread.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::ReadStdinLineQueue( void )
+{
+ // True when queue contains input
+ bool bHaveInput = false;
+
+ // Stores the current input line
+ CMIUtilString lineText;
+ {
+ // Lock while we access the queue
+ CMIUtilThreadLock lock( m_threadMutex );
+ if( !m_queueStdinLine.empty() )
+ {
+ lineText = m_queueStdinLine.front();
+ m_queueStdinLine.pop();
+ bHaveInput = !lineText.empty();
+ }
+ }
+
+ // Process while we have input
+ if( bHaveInput )
+ {
+ if( lineText == "quit" )
+ {
+ // We want to be exiting when receiving a quit command
+ m_bExitApp = true;
+ return MIstatus::success;
+ }
+
+ // Process the command
+ const bool bOk = InterpretCommand( lineText );
+
+ // Draw prompt if desired
+ if( bOk && m_rStdin.GetEnablePrompt() )
+ m_rStdOut.WriteMIResponse( m_rStdin.GetPrompt() );
+
+ // Input has been processed
+ bHaveInput = false;
+ }
+ else
+ {
+ // Give resources back to the OS
+ const std::chrono::milliseconds time( 1 );
+ std::this_thread::sleep_for( time );
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set things in motion, set state etc that brings *this driver (and the
+// application) to a tidy shutdown.
+// This function is used by the application's main thread.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::DoAppQuit( void )
+{
+ bool bYesQuit = true;
+
+ // Shutdown stuff, ready app for exit
+ {
+ CMIUtilThreadLock lock( m_threadMutex );
+ m_bDriverIsExiting = true;
+ }
+
+ return bYesQuit;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: *this driver passes text commands to a fall through driver is it does not
+// understand them (the LLDB driver).
+// This function is used by the application's main thread.
+// Type: Method.
+// Args: vTextLine - (R) Text data representing a possible command.
+// vwbCmdYesValid - (W) True = Command valid, false = command not handled.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::InterpretCommandFallThruDriver( const CMIUtilString & vTextLine, bool & vwbCmdYesValid )
+{
+ MIunused( vTextLine );
+ MIunused( vwbCmdYesValid );
+
+ // ToDo: Implement when less urgent work to be done or decide remove as not required
+ //bool bOk = MIstatus::success;
+ //bool bCmdNotUnderstood = true;
+ //if( bCmdNotUnderstood && GetEnableFallThru() )
+ //{
+ // CMIUtilString errMsg;
+ // bOk = DoFallThruToAnotherDriver( vStdInBuffer, errMsg );
+ // if( !bOk )
+ // {
+ // errMsg = errMsg.StripCREndOfLine();
+ // errMsg = errMsg.StripCRAll();
+ // const CMIDriverBase * pOtherDriver = GetDriverToFallThruTo();
+ // const MIchar * pName = pOtherDriver->GetDriverName().c_str();
+ // const MIchar * pId = pOtherDriver->GetDriverId().c_str();
+ // const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_FALLTHRU_DRIVER_ERR ), pName, pId, errMsg.c_str() ) );
+ // m_pLog->WriteMsg( msg );
+ // }
+ //}
+ //
+ //vwbCmdYesValid = bOk;
+ //CMIUtilString strNot;
+ //if( vwbCmdYesValid)
+ // strNot = CMIUtilString::Format( "%s ", MIRSRC( IDS_WORD_NOT ) );
+ //const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_FALLTHRU_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str() ) );
+ //m_pLog->WriteLog( msg );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the name for *this driver.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString & - Driver name.
+// Throws: None.
+//--
+const CMIUtilString & CMIDriver::GetDriverName( void ) const
+{
+ return GetName();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get the unique ID for *this driver.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString & - Text description.
+// Throws: None.
+//--
+const CMIUtilString & CMIDriver::GetDriverId( void ) const
+{
+ return GetId();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: This function allows *this driver to call on another driver to perform work
+// should this driver not be able to handle the client data input.
+// SetDriverToFallThruTo() specifies the fall through to driver.
+// Check the error message if the function returns a failure.
+// Type: Overridden.
+// Args: vCmd - (R) Command instruction to interpret.
+// vwErrMsg - (W) Error description on command failing.
+// Return: MIstatus::success - Command succeeded.
+// MIstatus::failure - Command failed.
+// Throws: None.
+//--
+bool CMIDriver::DoFallThruToAnotherDriver( const CMIUtilString & vCmd, CMIUtilString & vwErrMsg )
+{
+ bool bOk = MIstatus::success;
+
+ CMIDriverBase * pOtherDriver = GetDriverToFallThruTo();
+ if( pOtherDriver == nullptr )
+ return bOk;
+
+ return pOtherDriver->DoFallThruToAnotherDriver( vCmd, vwErrMsg );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: *this driver provides a file stream to other drivers on which *this driver
+// write's out to and they read as expected input. *this driver is passing
+// through commands to the (child) pass through assigned driver.
+// Type: Overrdidden.
+// Args: None.
+// Return: FILE * - Pointer to stream.
+// Throws: None.
+//--
+FILE * CMIDriver::GetStdin( void ) const
+{
+ // Note this fn is called on CMIDriverMgr register driver so stream has to be
+ // available before *this driver has been initialized! Flaw?
+
+ // This very likely to change later to a stream that the pass thru driver
+ // will read and we write to give it 'input'
+ return stdin;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: *this driver provides a file stream to other pass through assigned drivers
+// so they know what to write to.
+// Type: Overidden.
+// Args: None.
+// Return: FILE * - Pointer to stream.
+// Throws: None.
+//--
+FILE * CMIDriver::GetStdout( void ) const
+{
+ // Note this fn is called on CMIDriverMgr register driver so stream has to be
+ // available before *this driver has been initialized! Flaw?
+
+ // Do not want to pass through driver to write to stdout
+ return NULL;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: *this driver provides a error file stream to other pass through assigned drivers
+// so they know what to write to.
+// Type: Overidden.
+// Args: None.
+// Return: FILE * - Pointer to stream.
+// Throws: None.
+//--
+FILE * CMIDriver::GetStderr( void ) const
+{
+ // Note this fn is called on CMIDriverMgr register driver so stream has to be
+ // available before *this driver has been initialized! Flaw?
+
+ // This very likely to change later to a stream that the pass thru driver
+ // will write to and *this driver reads from to pass on the CMICmnLog object
+ return stderr;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set a unique ID for *this driver. It cannot be empty.
+// Type: Overridden.
+// Args: vId - (R) Text description.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::SetId( const CMIUtilString & vId )
+{
+ if( vId.empty() )
+ {
+ SetErrorDescriptionn( MIRSRC( IDS_DRIVER_ERR_ID_INVALID ), GetName().c_str(), vId.c_str() );
+ return MIstatus::failure;
+ }
+
+ m_strDriverId = vId;
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get the unique ID for *this driver.
+// Type: Overridden.
+// Args: None.
+// Return: CMIUtilString & - Text description.
+// Throws: None.
+//--
+const CMIUtilString & CMIDriver::GetId( void ) const
+{
+ return m_strDriverId;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Inject a command into the command processing system to be interpreted as a
+// command read from stdin. The text representing the command is also written
+// out to stdout as the command did not come from via stdin.
+// Type: Method.
+// Args: vMICmd - (R) Text data representing a possible command.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::InjectMICommand( const CMIUtilString & vMICmd )
+{
+ const bool bOk = m_rStdOut.WriteMIResponse( vMICmd );
+
+ return bOk && QueueMICommand( vMICmd );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add a new command candidate to the command queue to be processed by the
+// command system.
+// Type: Method.
+// Args: vMICmd - (R) Text data representing a possible command.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::QueueMICommand( const CMIUtilString & vMICmd )
+{
+ CMIUtilThreadLock lock( m_threadMutex );
+ m_queueStdinLine.push( vMICmd );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Interpret the text data and match against current commands to see if there
+// is a match. If a match then the command is issued and actioned on. The
+// text data if not understood by *this driver is past on to the Fall Thru
+// driver.
+// This function is used by the application's main thread.
+// Type: Method.
+// Args: vTextLine - (R) Text data representing a possible command.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::InterpretCommand( const CMIUtilString & vTextLine )
+{
+ bool bCmdYesValid = false;
+ bool bOk = InterpretCommandThisDriver( vTextLine, bCmdYesValid );
+ if( bOk && !bCmdYesValid )
+ bOk = InterpretCommandFallThruDriver( vTextLine, bCmdYesValid );
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Interpret the text data and match against current commands to see if there
+// is a match. If a match then the command is issued and actioned on. If a
+// command cannot be found to match then vwbCmdYesValid is set to false and
+// nothing else is done here.
+// This function is used by the application's main thread.
+// Type: Method.
+// Args: vTextLine - (R) Text data representing a possible command.
+// vwbCmdYesValid - (W) True = Command invalid, false = command acted on.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::InterpretCommandThisDriver( const CMIUtilString & vTextLine, bool & vwbCmdYesValid )
+{
+ vwbCmdYesValid = false;
+
+ bool bCmdNotInCmdFactor = false;
+ SMICmdData cmdData;
+ CMICmdMgr & rCmdMgr = CMICmdMgr::Instance();
+ if( !rCmdMgr.CmdInterpret( vTextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData ) )
+ return MIstatus::failure;
+
+ if( vwbCmdYesValid )
+ {
+ // For debugging only
+ //m_pLog->WriteLog( cmdData.strMiCmdAll.c_str() );
+
+ return ExecuteCommand( cmdData );
+ }
+
+ // Check for escape character, may be cursor control characters
+ // This code is not necessary for application operation, just want to keep tabs on what
+ // is been given to the driver to try and intepret.
+ if( vTextLine.at( 0 ) == 27 )
+ {
+ CMIUtilString logInput( MIRSRC( IDS_STDIN_INPUT_CTRL_CHARS ) );
+ for( MIuint i = 0; i < vTextLine.length(); i++ )
+ {
+ logInput += CMIUtilString::Format( "%d ", vTextLine.at( i ) );
+ }
+ m_pLog->WriteLog( logInput );
+ return MIstatus::success;
+ }
+
+ // Write to the Log that a 'command' was not valid.
+ // Report back to the MI client via MI result record.
+ CMIUtilString strNotInCmdFactory;
+ if( bCmdNotInCmdFactor )
+ strNotInCmdFactory = CMIUtilString::Format( MIRSRC( IDS_DRIVER_CMD_NOT_IN_FACTORY ), cmdData.strMiCmd.c_str() );
+ const CMIUtilString strNot( CMIUtilString::Format( "%s ", MIRSRC( IDS_WORD_NOT ) ) );
+ const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str() ) );
+ const CMICmnMIValueConst vconst = CMICmnMIValueConst( msg );
+ const CMICmnMIValueResult valueResult( "msg", vconst );
+ const CMICmnMIResultRecord miResultRecord( cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, valueResult );
+ m_rStdOut.WriteMIResponse( miResultRecord.GetString() );
+
+ // Proceed to wait for or execute next command
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Having previously had the potential command validated and found valid now
+// get the command executed.
+// This function is used by the application's main thread.
+// Type: Method.
+// Args: vCmdData - (RW) Command meta data.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriver::ExecuteCommand( const SMICmdData & vCmdData )
+{
+ CMICmdMgr & rCmdMgr = CMICmdMgr::Instance();
+ return rCmdMgr.CmdExecute( vCmdData );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set the MI Driver's exit application flag. The application checks this flag
+// after every stdin line is read so the exit may not be instantaneous.
+// If vbForceExit is false the MI Driver queries its state and determines if is
+// should exit or continue operating depending on that running state.
+// This is related to the running state of the MI driver.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMIDriver::SetExitApplicationFlag( const bool vbForceExit )
+{
+ if( vbForceExit )
+ {
+ CMIUtilThreadLock lock( m_threadMutex );
+ m_bExitApp = true;
+ return;
+ }
+
+ // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
+ // Did we receive a SIGINT from the client during a running debug program, if
+ // so then SIGINT is not to be taken as meaning kill the MI driver application
+ // but halt the inferior program being debugged instead
+ if( m_eCurrentDriverState == eDriverState_RunningDebugging )
+ {
+ InjectMICommand( "-exec-interrupt" );
+ return;
+ }
+
+ m_bExitApp = true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get the MI Driver's exit exit application flag.
+// This is related to the running state of the MI driver.
+// Type: Method.
+// Args: None.
+// Return: bool - True = MI Driver is shutting down, false = MI driver is running.
+// Throws: None.
+//--
+bool CMIDriver::GetExitApplicationFlag( void ) const
+{
+ return m_bExitApp;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get the current running state of the MI Driver.
+// Type: Method.
+// Args: None.
+// Return: DriverState_e - The current running state of the application.
+// Throws: None.
+//--
+CMIDriver::DriverState_e CMIDriver::GetCurrentDriverState( void ) const
+{
+ return m_eCurrentDriverState;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set the current running state of the MI Driver to running and currently not in
+// a debug session.
+// Type: Method.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Return: DriverState_e - The current running state of the application.
+// Throws: None.
+//--
+bool CMIDriver::SetDriverStateRunningNotDebugging( void )
+{
+ // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
+
+ if( m_eCurrentDriverState == eDriverState_RunningNotDebugging )
+ return MIstatus::success;
+
+ // Driver cannot be in the following states to set eDriverState_RunningNotDebugging
+ switch( m_eCurrentDriverState )
+ {
+ case eDriverState_NotRunning:
+ case eDriverState_Initialising:
+ case eDriverState_ShuttingDown:
+ {
+ SetErrorDescription( MIRSRC( IDS_DRIVER_ERR_DRIVER_STATE_ERROR ) );
+ return MIstatus::failure;
+ }
+ case eDriverState_RunningDebugging:
+ case eDriverState_RunningNotDebugging:
+ break;
+ case eDriverState_count:
+ default:
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CODE_ERR_INVALID_ENUMERATION_VALUE ), "SetDriverStateRunningNotDebugging()" ) );
+ return MIstatus::failure;
+ }
+
+ // Driver must be in this state to set eDriverState_RunningNotDebugging
+ if( m_eCurrentDriverState != eDriverState_RunningDebugging )
+ {
+ SetErrorDescription( MIRSRC( IDS_DRIVER_ERR_DRIVER_STATE_ERROR ) );
+ return MIstatus::failure;
+ }
+
+ m_eCurrentDriverState = eDriverState_RunningNotDebugging;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set the current running state of the MI Driver to running and currently not in
+// a debug session. The driver's state must in the state running and in a
+// debug session to set this new state.
+// Type: Method.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Return: DriverState_e - The current running state of the application.
+// Throws: None.
+//--
+bool CMIDriver::SetDriverStateRunningDebugging( void )
+{
+ // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
+
+ if( m_eCurrentDriverState == eDriverState_RunningDebugging )
+ return MIstatus::success;
+
+ // Driver cannot be in the following states to set eDriverState_RunningDebugging
+ switch( m_eCurrentDriverState )
+ {
+ case eDriverState_NotRunning:
+ case eDriverState_Initialising:
+ case eDriverState_ShuttingDown:
+ {
+ SetErrorDescription( MIRSRC( IDS_DRIVER_ERR_DRIVER_STATE_ERROR ) );
+ return MIstatus::failure;
+ }
+ case eDriverState_RunningDebugging:
+ case eDriverState_RunningNotDebugging:
+ break;
+ case eDriverState_count:
+ default:
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CODE_ERR_INVALID_ENUMERATION_VALUE ), "SetDriverStateRunningDebugging()" ) );
+ return MIstatus::failure;
+ }
+
+ // Driver must be in this state to set eDriverState_RunningDebugging
+ if( m_eCurrentDriverState != eDriverState_RunningNotDebugging )
+ {
+ SetErrorDescription( MIRSRC( IDS_DRIVER_ERR_DRIVER_STATE_ERROR ) );
+ return MIstatus::failure;
+ }
+
+ m_eCurrentDriverState = eDriverState_RunningDebugging;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Prepare the client IDE so it will start working/communicating with *this MI
+// driver.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMIDriver::InitClientIDEToMIDriver( void ) const
+{
+ // Put other IDE init functions here
+ return InitClientIDEEclipse();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: The IDE Eclipse when debugging locally expects "(gdb)\n" character
+// sequence otherwise it refuses to communicate and times out. This should be
+// sent to Eclipse before anything else.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMIDriver::InitClientIDEEclipse( void ) const
+{
+ std::cout << "(gdb)" << std::endl;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Ask *this driver whether it found an executable in the MI Driver's list of
+// arguments which to open and debug. If so instigate commands to set up a debug
+// session for that executable.
+// Type: Method.
+// Args: None.
+// Return: bool - True = True = Yes executable given as one of the parameters to the MI
+// Driver.
+// False = not found.
+// Throws: None.
+//--
+bool CMIDriver::HaveExecutableFileNamePathOnCmdLine( void ) const
+{
+ return m_bHaveExecutableFileNamePathOnCmdLine;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve from *this driver executable file name path to start a debug session
+// with (if present see HaveExecutableFileNamePathOnCmdLine()).
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - Executeable file name path or empty string.
+// Throws: None.
+//--
+const CMIUtilString & CMIDriver::GetExecutableFileNamePathOnCmdLine( void ) const
+{
+ return m_strCmdLineArgExecuteableFileNamePath;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Execute commands (by injecting them into the stdin line queue container) and
+// other code to set up the MI Driver such that is can take the executable
+// argument passed on the command and create a debug session for it.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functionality succeeded.
+// MIstatus::failure - Functionality failed.
+// Throws: None.
+//--
+bool CMIDriver::LocalDebugSessionStartupInjectCommands( void )
+{
+ const CMIUtilString strCmd( CMIUtilString::Format( "-file-exec-and-symbols %s", m_strCmdLineArgExecuteableFileNamePath.c_str() ) );
+
+ return InjectMICommand( strCmd );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set the MI Driver into "its debugging an executable passed as an argument"
+// mode as against running via a client like Eclipse.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMIDriver::SetDriverDebuggingArgExecutable( void )
+{
+ m_bDriverDebuggingArgExecutable = true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the MI Driver state indicating if it is operating in "its debugging
+// an executable passed as an argument" mode as against running via a client
+// like Eclipse.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+bool CMIDriver::IsDriverDebuggingArgExecutable( void ) const
+{
+ return m_bDriverDebuggingArgExecutable;
+}
+
diff --git a/tools/lldb-mi/MIDriver.h b/tools/lldb-mi/MIDriver.h
new file mode 100644
index 000000000000..c565e825096e
--- /dev/null
+++ b/tools/lldb-mi/MIDriver.h
@@ -0,0 +1,182 @@
+//===-- MIDriver.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIDriver.h
+//
+// Overview: CMIDriver interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers
+#include <queue>
+
+// In-house headers:
+#include "MICmnConfig.h"
+#include "MICmnBase.h"
+#include "MIDriverBase.h"
+#include "MIDriverMgr.h"
+#include "MICmnStreamStdin.h"
+#include "MICmdData.h"
+#include "MIUtilSingletonBase.h"
+
+// Declarations:
+class CMICmnLLDBDebugger;
+class CMICmnStreamStdout;
+
+//++ ============================================================================
+// Details: MI driver implementation class. A singleton class derived from
+// LLDB SBBroadcaster class. Register the instance of *this class with
+// the CMIDriverMgr. The CMIDriverMgr sets the driver(s) of to start
+// work depending on the one selected to work. A driver can if not able
+// to handle an instruction or 'command' can pass that command onto
+// another driver object registered with the Driver Manager.
+// Gotchas: None.
+// Authors: Illya Rudkin 29/01/2014.
+// Changes: None.
+//--
+class CMIDriver
+: public CMICmnBase
+, public CMIDriverMgr::IDriver
+, public CMIDriverBase
+, public CMICmnStreamStdin::IStreamStdin
+, public MI::ISingleton< CMIDriver >
+{
+ friend class MI::ISingleton< CMIDriver >;
+
+// Enumerations:
+public:
+ //++ ----------------------------------------------------------------------
+ // Details: The MI Driver has a running state which is used to help determin
+ // which specific action(s) it should take or not allow.
+ // The driver when operational and not shutting down alternates
+ // between eDriverState_RunningNotDebugging and
+ // eDriverState_RunningDebugging. eDriverState_RunningNotDebugging
+ // is normally set when a breakpoint is hit or halted.
+ // eDriverState_RunningDebugging is normally set when "exec-continue"
+ // or "exec-run" is issued.
+ //--
+ enum DriverState_e
+ {
+ eDriverState_NotRunning = 0, // The MI Driver is not operating
+ eDriverState_Initialising, // The MI Driver is setting itself up
+ eDriverState_RunningNotDebugging, // The MI Driver is operational acting on any MI commands sent to it
+ eDriverState_RunningDebugging, // The MI Driver is currently overseeing an inferior program that is running
+ eDriverState_ShuttingDown, // The MI Driver is tearing down resources and about exit
+ eDriverState_count // Always last
+ };
+
+// Methods:
+public:
+ // MI system
+ bool Initialize( void );
+ bool Shutdown( void );
+
+ // MI state
+ bool GetExitApplicationFlag( void ) const;
+ DriverState_e GetCurrentDriverState( void ) const;
+ bool SetDriverStateRunningNotDebugging( void );
+ bool SetDriverStateRunningDebugging( void );
+ void SetDriverDebuggingArgExecutable( void );
+ bool IsDriverDebuggingArgExecutable( void ) const;
+
+ // MI information about itself
+ const CMIUtilString & GetAppNameShort( void ) const;
+ const CMIUtilString & GetAppNameLong( void ) const;
+ const CMIUtilString & GetVersionDescription( void ) const;
+
+ // MI do work
+ bool WriteMessageToLog( const CMIUtilString & vMessage );
+ bool SetEnableFallThru( const bool vbYes );
+ bool GetEnableFallThru( void ) const;
+ bool InjectMICommand( const CMIUtilString & vMICmd );
+ bool HaveExecutableFileNamePathOnCmdLine( void ) const;
+ const CMIUtilString & GetExecutableFileNamePathOnCmdLine( void ) const;
+
+// Overridden:
+public:
+ // From CMIDriverMgr::IDriver
+ virtual bool DoInitialize( void );
+ virtual bool DoShutdown( void );
+ virtual bool DoMainLoop( void );
+ virtual void DoResizeWindow( const uint32_t vWindowSizeWsCol );
+ virtual lldb::SBError DoParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting );
+ virtual CMIUtilString GetError( void ) const;
+ virtual const CMIUtilString & GetName( void ) const;
+ virtual lldb::SBDebugger & GetTheDebugger( void );
+ virtual bool GetDriverIsGDBMICompatibleDriver( void ) const;
+ virtual bool SetId( const CMIUtilString & vId );
+ virtual const CMIUtilString & GetId( void ) const;
+ // From CMIDriverBase
+ virtual void SetExitApplicationFlag( const bool vbForceExit );
+ virtual bool DoFallThruToAnotherDriver( const CMIUtilString & vCmd, CMIUtilString & vwErrMsg );
+ virtual bool SetDriverToFallThruTo( const CMIDriverBase & vrOtherDriver );
+ virtual FILE * GetStdin( void ) const;
+ virtual FILE * GetStdout( void ) const;
+ virtual FILE * GetStderr( void ) const;
+ virtual const CMIUtilString & GetDriverName( void ) const;
+ virtual const CMIUtilString & GetDriverId( void ) const;
+ // From CMICmnStreamStdin
+ virtual bool ReadLine( const CMIUtilString & vStdInBuffer, bool & vrbYesExit );
+
+// Typedefs:
+private:
+ typedef std::queue< CMIUtilString > QueueStdinLine_t;
+
+// Methods:
+private:
+ /* ctor */ CMIDriver( void );
+ /* ctor */ CMIDriver( const CMIDriver & );
+ void operator=( const CMIDriver & );
+
+ lldb::SBError ParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting );
+ bool ReadStdinLineQueue( void );
+ bool DoAppQuit( void );
+ bool InterpretCommand( const CMIUtilString & vTextLine );
+ bool InterpretCommandThisDriver( const CMIUtilString & vTextLine, bool & vwbCmdYesValid );
+ bool InterpretCommandFallThruDriver( const CMIUtilString & vTextLine, bool & vwbCmdYesValid );
+ bool ExecuteCommand( const SMICmdData & vCmdData );
+ bool StartWorkerThreads( void );
+ bool StopWorkerThreads( void );
+ bool InitClientIDEToMIDriver( void ) const;
+ bool InitClientIDEEclipse( void ) const;
+ bool QueueMICommand( const CMIUtilString & vMICmd );
+ bool LocalDebugSessionStartupInjectCommands( void );
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMIDriver( void );
+
+// Attributes:
+private:
+ static const CMIUtilString ms_constAppNameShort;
+ static const CMIUtilString ms_constAppNameLong;
+ static const CMIUtilString ms_constMIVersion;
+ //
+ bool m_bFallThruToOtherDriverEnabled; // True = yes fall through, false = do not pass on command
+ CMIUtilThreadMutex m_threadMutex;
+ QueueStdinLine_t m_queueStdinLine; // Producer = stdin monitor, consumer = *this driver
+ bool m_bDriverIsExiting; // True = yes, driver told to quit, false = continue working
+ void * m_handleMainThread; // *this driver is run by the main thread
+ CMICmnStreamStdin & m_rStdin;
+ CMICmnLLDBDebugger & m_rLldbDebugger;
+ CMICmnStreamStdout & m_rStdOut;
+ DriverState_e m_eCurrentDriverState;
+ bool m_bHaveExecutableFileNamePathOnCmdLine; // True = Yes executable given as one of the parameters to the MI Driver, false = not found
+ CMIUtilString m_strCmdLineArgExecuteableFileNamePath;
+ bool m_bDriverDebuggingArgExecutable; // True = The MI Driver (MI mode) is debugging executable passed as argument, false = running via a client i.e Eclipse
+};
diff --git a/tools/lldb-mi/MIDriverBase.cpp b/tools/lldb-mi/MIDriverBase.cpp
new file mode 100644
index 000000000000..353f5c32a164
--- /dev/null
+++ b/tools/lldb-mi/MIDriverBase.cpp
@@ -0,0 +1,195 @@
+//===-- MIDriverBase.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIDriverBase.cpp
+//
+// Overview: CMIDriverBase implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third party headers:
+#include <lldb/API/SBEvent.h>
+#include <lldb/API/SBBroadcaster.h>
+
+// In-house headers:
+#include "MIDriverBase.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIDriverBase constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIDriverBase::CMIDriverBase( void )
+: m_pDriverFallThru( nullptr )
+, m_pDriverParent( nullptr )
+, m_bExitApp( false )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIDriverBase destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIDriverBase::~CMIDriverBase( void )
+{
+ m_pDriverFallThru = NULL;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: This function allows *this driver to call on another driver to perform work
+// should this driver not be able to handle the client data input.
+// Type: Overrideable.
+// Check the error message if the function returns a failure.
+// Type: Overridden.
+// Args: vCmd - (R) Command instruction to interpret.
+// vwErrMsg - (W) Error description on command failing.
+// Return: MIstatus::success - Command succeeded.
+// MIstatus::failure - Command failed.
+// Throws: None.
+//--
+bool CMIDriverBase::DoFallThruToAnotherDriver( const CMIUtilString & vCmd, CMIUtilString & vwErrMsg )
+{
+ // Do nothing - override and implement. Use m_pDriverFallThru.
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: This function allows *this driver to call on another driver to perform work
+// should this driver not be able to handle the client data input.
+// Type: Overrideable.
+// Args: vrOtherDriver - (R) Reference to another driver object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriverBase::SetDriverToFallThruTo( const CMIDriverBase & vrOtherDriver )
+{
+ MIunused( vrOtherDriver );
+
+ // Do nothing - override and implement. Set m_pDriverFallThru.
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: This function allows *this driver to call functionality on the parent driver
+// ask for information for example.
+// Type: Overrideable.
+// Args: vrOtherDriver - (R) Reference to another driver object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriverBase::SetDriverParent( const CMIDriverBase & vrOtherDriver )
+{
+ MIunused( vrOtherDriver );
+
+ // Do nothing - override and implement. Set m_pDriverParent.
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the parent driver to *this driver if one assigned. If assigned *this
+// is the pass through driver that the parent driver passes work to.
+// Type: Method.
+// Args: None.
+// Return: CMIDriverBase * - Pointer to a driver object.
+// - NULL = there is not parent to *this driver.
+// Throws: None.
+//--
+CMIDriverBase * CMIDriverBase::GetDriversParent( void ) const
+{
+ return m_pDriverParent;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the pointer to the other fall through driver *this driver is using
+// (or not using).
+// Type: Method.
+// Args: None.
+// Return: CMIDriverBase * - Pointer to other driver.
+// - NULL if no driver set.
+// Throws: None.
+//--
+CMIDriverBase * CMIDriverBase::GetDriverToFallThruTo( void ) const
+{
+ return m_pDriverFallThru;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: *this driver provides a file stream to other drivers on which *this driver
+// write's out to and they read as expected input. *this driver is passing
+// through commands to the (child) pass through assigned driver.
+// Type: Overrideable.
+// Args: None.
+// Return: FILE * - Pointer to stream.
+// Throws: None.
+//--
+FILE * CMIDriverBase::GetStdin( void ) const
+{
+ // Do nothing - override and implement
+ return nullptr;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: *this driver provides a file stream to other pass through assigned drivers
+// so they know what to write to.
+// Type: Overrideable.
+// Args: None.
+// Return: FILE * - Pointer to stream.
+// Throws: None.
+//--
+FILE * CMIDriverBase::GetStdout( void ) const
+{
+ // Do nothing - override and implement
+ return nullptr;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: *this driver provides a error file stream to other pass through assigned drivers
+// so they know what to write to.
+// Type: Overrideable.
+// Args: None.
+// Return: FILE * - Pointer to stream.
+// Throws: None.
+//--
+FILE * CMIDriverBase::GetStderr( void ) const
+{
+ // Do nothing - override and implement
+ return nullptr;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set the MI Driver's exit application flag. The application checks this flag
+// after every stdin line is read so the exit may not be instantious.
+// If vbForceExit is false the MI Driver queries its state and determines if is
+// should exit or continue operating depending on that running state.
+// Type: Overrideable.
+// Args: vbForceExit - (R) True = Do not query, set state to exit, false = query if can/should exit right now.
+// Return: None.
+// Throws: None.
+//--
+void CMIDriverBase::SetExitApplicationFlag( const bool vbForceExit )
+{
+ MIunused( vbForceExit );
+
+ // Do nothing - override and implement
+} \ No newline at end of file
diff --git a/tools/lldb-mi/MIDriverBase.h b/tools/lldb-mi/MIDriverBase.h
new file mode 100644
index 000000000000..ed6b930cfd83
--- /dev/null
+++ b/tools/lldb-mi/MIDriverBase.h
@@ -0,0 +1,78 @@
+//===-- MIDriverBase.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIDriverBase.h
+//
+// Overview: CMIDriverBase interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <lldb/API/SBDebugger.h>
+#include <lldb/API/SBBroadcaster.h>
+
+// In-house headers:
+#include "MIUtilString.h"
+
+// Declarations:
+namespace lldb { class SBBroadcaster; }
+
+//++ ============================================================================
+// Details: MI driver base implementation class. This class has been created so
+// not have to edit the lldb::SBBroadcaster class code. Functionality
+// and attributes need to be common to the LLDB Driver class and the
+// MI Driver class (derived from lldb::SBBroadcaster) so they can call
+// upon each other for functionality fall through and allow the
+// CDriverMgr to manage either (any) driver to be operated on.
+// Each driver instance (the CMIDriver, LLDB::Driver) has its own
+// LLDB::SBDebugger object.
+// Gotchas: None.
+// Authors: Illya Rudkin 30/01/2014.
+// Changes: None.
+//--
+class CMIDriverBase
+{
+// Methods:
+public:
+ /* ctor */ CMIDriverBase( void );
+
+ CMIDriverBase * GetDriverToFallThruTo( void ) const;
+ CMIDriverBase * GetDriversParent( void ) const;
+
+// Overrideable:
+public:
+ /* dtor */ virtual ~CMIDriverBase( void );
+
+ virtual bool DoFallThruToAnotherDriver( const CMIUtilString & vCmd, CMIUtilString & vwErrMsg );
+ virtual bool SetDriverToFallThruTo( const CMIDriverBase & vrOtherDriver );
+ virtual bool SetDriverParent( const CMIDriverBase & vrOtherDriver );
+ virtual const CMIUtilString & GetDriverName( void ) const = 0;
+ virtual const CMIUtilString & GetDriverId( void ) const = 0;
+ virtual void SetExitApplicationFlag( const bool vbForceExit );
+
+ // MI provide information for the pass through (child) assigned driver
+ virtual FILE * GetStdin( void ) const;
+ virtual FILE * GetStdout( void ) const;
+ virtual FILE * GetStderr( void ) const;
+
+// Attributes:
+protected:
+ CMIDriverBase * m_pDriverFallThru; // Child driver to use should *this driver not be able to handle client input
+ CMIDriverBase * m_pDriverParent; // The parent driver who passes work to *this driver to do work
+ CMIUtilString m_strDriverId;
+ bool m_bExitApp; // True = Yes, exit application, false = continue execution
+};
diff --git a/tools/lldb-mi/MIDriverMain.cpp b/tools/lldb-mi/MIDriverMain.cpp
new file mode 100644
index 000000000000..a72e4ab20f3d
--- /dev/null
+++ b/tools/lldb-mi/MIDriverMain.cpp
@@ -0,0 +1,393 @@
+//===-- MIDriverMain.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIDriverMain.cpp
+//
+// Overview: Defines the entry point for the console application.
+// The MI application (project name MI) runs in two modes:
+// An LLDB native driver mode where it acts no different from the LLDB driver.
+// The other mode is the MI when it finds on the command line
+// the --interpreter option. Command line argument --help on its own will give
+// help for the LLDB driver. If entered with --interpreter then MI help will
+// provided.
+// To implement new MI commands derive a new command class from the command base
+// class. To enable the new command for interpretation add the new command class
+// to the command factory. The files of relevance are:
+// MICmdCommands.cpp
+// MICmdBase.h / .cpp
+// MICmdCmd.h / .cpp
+// Versions: 1.0.0.1 First version from scratch 28/1/2014 to 28/3/2014. MI not complete.
+// 1.0.0.2 First deliverable to client 7/3/2014. MI not complete.
+// 1.0.0.3 Code refactor tidy. Release to community for evaluation 17/5/2014. MI not complete.
+// 1.0.0.4 Post release to the community for evaluation 17/5/2014. MI not complete.
+// 1.0.0.5 Second deliverable to client 16/6/2014.
+// 1.0.0.6 Post release of second deliverable to client 16/6/2014.
+// Released to the community 24/6/2014.
+// 1.0.0.7 Post release to the community.
+// Delivered to client 30/6/2014.
+// 1.0.0.8 Delivered to client 29/7/2014.
+// 1.0.0.9 Post release to client 29/7/2014.
+// See MIreadme.txt for list of MI commands implemented.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadme.txt.
+//
+// Copyright: None.
+//--
+
+#if defined( _MSC_VER )
+ #define _INC_SIGNAL // Stop window's signal.h being included - CODETAG_IOR_SIGNALS
+#endif // _MSC_VER
+
+// Third party headers:
+#include <stdio.h>
+#include <lldb/API/SBHostOS.h>
+
+// In house headers:
+#include "MICmnConfig.h"
+#include "Platform.h" // Define signals - CODETAG_IOR_SIGNALS
+#include "Driver.h"
+#include "MIDriverMgr.h"
+#include "MIDriver.h"
+#include "MICmnResources.h"
+#include "MICmnStreamStdin.h"
+#include "MIUtilDebug.h"
+#include "MICmnLog.h"
+
+#if MICONFIG_COMPILE_MIDRIVER_VERSION
+
+#if defined( _MSC_VER )
+#pragma warning( once : 4530 ) // Warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
+#endif // _MSC_VER
+
+// ToDo: Reevaluate if this function needs to be implemented like the UNIX equivalent
+// CODETAG_IOR_SIGNALS
+//++ ------------------------------------------------------------------------------------
+// Details: The SIGWINCH signal is sent to a process when its controlling terminal
+// changes its size (a window change).
+// Type: Function.
+// Args: vSigno - (R) Signal number.
+// Return: None.
+// Throws: None.
+//--
+void sigwinch_handler( int vSigno )
+{
+ MIunused( vSigno );
+
+ struct winsize window_size;
+ if( ::isatty( STDIN_FILENO ) && ::ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) == 0 )
+ {
+ CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance();
+ if( window_size.ws_col > 0 )
+ {
+ rDriverMgr.DriverResizeWindow( (uint32_t) window_size.ws_col );
+ }
+ }
+
+ CMICmnLog::Instance().WriteLog( CMIUtilString::Format( MIRSRC( IDS_PROCESS_SIGNAL_RECEIVED ), "SIGWINCH", vSigno ) );
+}
+
+// CODETAG_IOR_SIGNALS
+//++ ------------------------------------------------------------------------------------
+// Details: The SIGINT signal is sent to a process by its controlling terminal when a
+// user wishes to interrupt the process. This is typically initiated by pressing
+// Control-C, but on some systems, the "delete" character or "break" key can be
+// used.
+// Be aware this function may be called on another thread besides the main thread.
+// Type: Function.
+// Args: vSigno - (R) Signal number.
+// Return: None.
+// Throws: None.
+//--
+void sigint_handler( int vSigno )
+{
+ static bool g_interrupt_sent = false;
+ CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance();
+ lldb::SBDebugger * pDebugger = rDriverMgr.DriverGetTheDebugger();
+ if( pDebugger != nullptr )
+ {
+ if( !g_interrupt_sent )
+ {
+ g_interrupt_sent = true;
+ pDebugger->DispatchInputInterrupt();
+ g_interrupt_sent = false;
+ }
+ }
+
+ CMICmnLog::Instance().WriteLog( CMIUtilString::Format( MIRSRC( IDS_PROCESS_SIGNAL_RECEIVED ), "SIGINT", vSigno ) );
+
+ // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
+ // Signal MI to shutdown or halt a running debug session
+ CMICmnStreamStdin::Instance().SetCtrlCHit();
+}
+
+// ToDo: Reevaluate if this function needs to be implemented like the UNIX equivalent
+// CODETAG_IOR_SIGNALS
+//++ ------------------------------------------------------------------------------------
+// Details: The SIGTSTP signal is sent to a process by its controlling terminal to
+// request it to stop temporarily. It is commonly initiated by the user pressing
+// Control-Z. Unlike SIGSTOP, the process can register a signal handler for or
+// ignore the signal.
+// *** The function does not behave ATM like the UNIX equivalent ***
+// Type: Function.
+// Args: vSigno - (R) Signal number.
+// Return: None.
+// Throws: None.
+//--
+void sigtstp_handler( int vSigno )
+{
+ CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance();
+ lldb::SBDebugger * pDebugger = rDriverMgr.DriverGetTheDebugger();
+ if( pDebugger != nullptr )
+ {
+ pDebugger->SaveInputTerminalState();
+ }
+
+ CMICmnLog::Instance().WriteLog( CMIUtilString::Format( MIRSRC( IDS_PROCESS_SIGNAL_RECEIVED ), "SIGTSTP", vSigno ) );
+
+ // Signal MI to shutdown
+ CMICmnStreamStdin::Instance().SetCtrlCHit();
+}
+
+// ToDo: Reevaluate if this function needs to be implemented like the UNIX equivalent
+// CODETAG_IOR_SIGNALS
+//++ ------------------------------------------------------------------------------------
+// Details: The SIGCONT signal instructs the operating system to continue (restart) a
+// process previously paused by the SIGSTOP or SIGTSTP signal. One important use
+// of this signal is in job control in the UNIX shell.
+// *** The function does not behave ATM like the UNIX equivalent ***
+// Type: Function.
+// Args: vSigno - (R) Signal number.
+// Return: None.
+// Throws: None.
+//--
+void sigcont_handler( int vSigno )
+{
+ CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance();
+ lldb::SBDebugger * pDebugger = rDriverMgr.DriverGetTheDebugger();
+ if( pDebugger != nullptr )
+ {
+ pDebugger->RestoreInputTerminalState();
+ }
+
+ CMICmnLog::Instance().WriteLog( CMIUtilString::Format( MIRSRC( IDS_PROCESS_SIGNAL_RECEIVED ), "SIGCONT", vSigno ) );
+
+ // Signal MI to shutdown
+ CMICmnStreamStdin::Instance().SetCtrlCHit();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Init the MI driver system. Initialize the whole driver system which includes
+// both the original LLDB driver and the MI driver.
+// Type: Function.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool DriverSystemInit( void )
+{
+ bool bOk = MIstatus::success;
+
+#if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
+ Driver * pDriver = Driver::CreateSelf();
+ if( pDriver == nullptr )
+ return MIstatus::failure;
+#endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
+
+ CMIDriver & rMIDriver = CMIDriver::Instance();
+ CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance();
+ bOk = rDriverMgr.Initialize();
+
+ // Register MIDriver first as it needs to initialize and be ready
+ // for the Driver to get information from MIDriver when it initializes
+ // (LLDB Driver is registered with the Driver Manager in MI's Initialize())
+ bOk = bOk && rDriverMgr.RegisterDriver( rMIDriver, "MIDriver" ); // Will be main driver
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Shutdown the debugger system. Release / terminate resources external to
+// specifically the MI driver.
+// Type: Function.
+// Args: vbAppExitOk - (R) True = No problems, false = App exiting with problems (investigate!).
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool DriverSystemShutdown( const bool vbAppExitOk )
+{
+ bool bOk = MIstatus::success;
+
+ // *** Order is important here ***
+ CMIDriverMgr::Instance().Shutdown();
+
+#if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
+ delete g_driver;
+ g_driver = nullptr;
+#endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
+
+ return bOk;
+}
+
+#else
+void
+sigwinch_handler (int signo)
+{
+ struct winsize window_size;
+ if (isatty (STDIN_FILENO)
+ && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
+ {
+ if ((window_size.ws_col > 0) && g_driver != NULL)
+ {
+ g_driver->ResizeWindow (window_size.ws_col);
+ }
+ }
+}
+
+void
+sigint_handler (int signo)
+{
+ static bool g_interrupt_sent = false;
+ if (g_driver)
+ {
+ if (!g_interrupt_sent)
+ {
+ g_interrupt_sent = true;
+ g_driver->GetDebugger().DispatchInputInterrupt();
+ g_interrupt_sent = false;
+ return;
+ }
+ }
+
+ exit (signo);
+}
+
+void
+sigtstp_handler (int signo)
+{
+ g_driver->GetDebugger().SaveInputTerminalState();
+ signal (signo, SIG_DFL);
+ kill (getpid(), signo);
+ signal (signo, sigtstp_handler);
+}
+
+void
+sigcont_handler (int signo)
+{
+ g_driver->GetDebugger().RestoreInputTerminalState();
+ signal (signo, SIG_DFL);
+ kill (getpid(), signo);
+ signal (signo, sigcont_handler);
+}
+#endif // #if MICONFIG_COMPILE_MIDRIVER_VERSION
+
+//++ ------------------------------------------------------------------------------------
+// Details: MI's application start point of execution. The applicaton runs in two modes.
+// An LLDB native driver mode where it acts no different from the LLDB driver.
+// The other mode is the MI when it finds on the command line
+// the --interpreter option. Command line argument --help on its own will give
+// help for the LLDB driver. If entered with --interpreter then application
+// help will provided.
+// Type: Method.
+// Args: argc - (R) An integer that contains the count of arguments that follow in
+// argv. The argc parameter is always greater than or equal to 1.
+// argv - (R) An array of null-terminated strings representing command-line
+// arguments entered by the user of the program. By convention,
+// argv[0] is the command with which the program is invoked.
+// Return: int - 0 = Normal exit, program success.
+// >0 = Program success with status i.e. Control-C signal status
+// <0 = Program failed.
+// -1 = Program failed reason not specified here, see MI log file.
+// -1000 = Program failed did not initailize successfully.
+// Throws: None.
+//--
+#if MICONFIG_COMPILE_MIDRIVER_VERSION
+int main( int argc, char const *argv[] )
+{
+#if MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG
+#ifdef _WIN32
+ CMIUtilDebug::ShowDlgWaitForDbgAttach();
+#else
+ CMIUtilDebug::WaitForDbgAttachInfinteLoop();
+#endif // _WIN32
+#endif // MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG
+
+ // *** Order is important here ***
+ bool bOk = DriverSystemInit();
+ if( !bOk )
+ {
+ DriverSystemShutdown( bOk );
+ return -1000;
+ }
+
+ // CODETAG_IOR_SIGNALS
+ signal( SIGPIPE, SIG_IGN );
+ signal( SIGWINCH, sigwinch_handler );
+ signal( SIGINT, sigint_handler );
+ signal( SIGTSTP, sigtstp_handler );
+ signal( SIGCONT, sigcont_handler );
+
+ bool bExiting = false;
+ CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance();
+ bOk = bOk && rDriverMgr.ParseArgs( argc, argv, bExiting );
+ if( bOk && !bExiting )
+ bOk = rDriverMgr.DriverParseArgs( argc, argv, stdout, bExiting );
+ if( bOk && !bExiting )
+ bOk = rDriverMgr.DriverMainLoop();
+
+ // Logger and other resources shutdown now
+ DriverSystemShutdown( bOk );
+
+ const int appResult = bOk ? 0 : -1;
+
+ return appResult;
+}
+#else // Operate the lldb Driver only version of the code
+int main(int argc, char const *argv[], char *envp[])
+{
+ MIunused( envp );
+ using namespace lldb;
+ SBDebugger::Initialize();
+
+ SBHostOS::ThreadCreated ("<lldb.driver.main-thread>");
+
+ signal (SIGPIPE, SIG_IGN);
+ signal (SIGWINCH, sigwinch_handler);
+ signal (SIGINT, sigint_handler);
+ signal (SIGTSTP, sigtstp_handler);
+ signal (SIGCONT, sigcont_handler);
+
+ // Create a scope for driver so that the driver object will destroy itself
+ // before SBDebugger::Terminate() is called.
+ {
+ Driver driver;
+
+ bool exiting = false;
+ SBError error (driver.ParseArgs (argc, argv, stdout, exiting));
+ if (error.Fail())
+ {
+ const char *error_cstr = error.GetCString ();
+ if (error_cstr)
+ ::fprintf (stderr, "error: %s\n", error_cstr);
+ }
+ else if (!exiting)
+ {
+ driver.MainLoop();
+ }
+ }
+
+ SBDebugger::Terminate();
+ return 0;
+}
+#endif // MICONFIG_COMPILE_MIDRIVER_VERSION
+
diff --git a/tools/lldb-mi/MIDriverMgr.cpp b/tools/lldb-mi/MIDriverMgr.cpp
new file mode 100644
index 000000000000..b5cb7d4b5151
--- /dev/null
+++ b/tools/lldb-mi/MIDriverMgr.cpp
@@ -0,0 +1,762 @@
+//===-- MIDriverMgr.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIDriverMgr.cpp
+//
+// Overview: CMIDriverMgr implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third Party Headers:
+#include <lldb/API/SBError.h>
+
+// In-house headers:
+#include "MIDriverMgr.h"
+#include "MICmnResources.h"
+#include "MICmnLog.h"
+#include "MICmnLogMediumFile.h"
+#include "MIDriver.h"
+#include "MIUtilTermios.h"
+#include "MICmnStreamStdout.h"
+#include "MIUtilSingletonHelper.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIDriverMgr constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIDriverMgr::CMIDriverMgr( void )
+: m_pDriverCurrent( nullptr )
+, m_bInMi2Mode( false )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIDriverMgr destructor.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIDriverMgr::~CMIDriverMgr( void )
+{
+ Shutdown();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Initialize *this manager.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriverMgr::Initialize( void )
+{
+ m_clientUsageRefCnt++;
+
+ ClrErrorDescription();
+
+ if( m_bInitialized )
+ return MIstatus::success;
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Note initialisation order is important here as some resources depend on previous
+ MI::ModuleInit< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg );
+ MI::ModuleInit< CMICmnResources >( IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg );
+
+ if( bOk )
+ {
+ MIUtilTermios::StdinTermiosSet();
+ }
+
+ m_bInitialized = bOk;
+
+ if( !bOk )
+ {
+ CMIUtilString strInitError( CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_DRIVERMGR ), errMsg.c_str() ) );
+ SetErrorDescription( strInitError );
+ return MIstatus::failure;
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Unbind detach or release resources used by this server in general common
+// functionality shared between versions of any server interfaces implemented.
+// Type: Method.
+// Args: vbAppExitOk - (R) True = No problems, false = App exiting with problems (investigate!).
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriverMgr::Shutdown( void )
+{
+ // Do not want a ref counter because this function needs to be called how ever this
+ // application stops running
+ //if( --m_clientUsageRefCnt > 0 )
+ // return MIstatus::success;
+
+ bool vbAppExitOk = true;
+
+ ClrErrorDescription();
+
+ if( !m_bInitialized )
+ return MIstatus::success;
+
+ if( vbAppExitOk )
+ {
+ // The MI Driver's log updating may have been switched off switch back on to say all is ok.
+ CMICmnLog::Instance().SetEnabled( true );
+#if _DEBUG
+ CMICmnStreamStdout::Instance().Write( MIRSRC( IDE_MI_APP_EXIT_OK ) ); // Both stdout and Log
+#else
+ CMICmnLog::WriteLog( MIRSRC( IDE_MI_APP_EXIT_OK ) ); // Just to the Log
+#endif // _DEBUG
+ }
+ else
+ {
+ CMICmnLog & rAppLog = CMICmnLog::Instance();
+ if( rAppLog.GetEnabled() )
+ {
+ const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDE_MI_APP_EXIT_WITH_PROBLEM ), CMICmnLogMediumFile::Instance().GetFileName().c_str() ) );
+ CMICmnStreamStdout::Instance().Write( msg );
+ }
+ else
+ {
+ // The MI Driver's log updating may have been switched off switch back on to say there has been problem.
+ rAppLog.SetEnabled( true );
+ const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDE_MI_APP_EXIT_WITH_PROBLEM_NO_LOG ), CMICmnLogMediumFile::Instance().GetFileName().c_str() ) );
+ CMICmnStreamStdout::Instance().Write( msg );
+ }
+ }
+
+ m_bInitialized = false;
+
+ bool bOk = MIstatus::success;
+ CMIUtilString errMsg;
+
+ // Tidy up
+ UnregisterDriverAll();
+ MIUtilTermios::StdinTermiosReset();
+
+ // Note shutdown order is important here
+ MI::ModuleShutdown< CMICmnResources >( IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg );
+ MI::ModuleShutdown< CMICmnLog > ( IDS_MI_SHTDWN_ERR_LOG , bOk, errMsg );
+
+ if( !bOk )
+ {
+ SetErrorDescriptionn( MIRSRC( IDS_MI_SHTDWN_ERR_DRIVERMGR ), errMsg.c_str() );
+ }
+
+ return bOk;
+}
+//++ ------------------------------------------------------------------------------------
+// Details: Unregister all the Driver registered with *this manager. The manager also
+// deletes
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriverMgr::UnregisterDriverAll( void )
+{
+ MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
+ while( it != m_mapDriverIdToDriver.end() )
+ {
+ IDriver * pDriver = (*it).second;
+ pDriver->DoShutdown();
+
+ // Next
+ ++it;
+ }
+
+ m_mapDriverIdToDriver.clear();
+ m_pDriverCurrent = NULL;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Register a driver with *this Driver Manager. Call SetUseThisDriverToDoWork()
+// inform the manager which driver is the one to the work. The manager calls
+// the driver's init function which must be successful in order to complete the
+// registration.
+// Type: Method.
+// Args: vrDriver - (R) The driver to register.
+// vrDriverID - (R) The driver's ID to lookup by.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriverMgr::RegisterDriver( const IDriver & vrDriver, const CMIUtilString & vrDriverID )
+{
+ if( HaveDriverAlready( vrDriver ) )
+ return MIstatus::success;
+
+ IDriver * pDriver = const_cast< IDriver * >( &vrDriver );
+ if( !pDriver->SetId( vrDriverID ) )
+ return MIstatus::failure;
+ if( !pDriver->DoInitialize() )
+ {
+ SetErrorDescriptionn( MIRSRC( IDS_DRIVERMGR_DRIVER_ERR_INIT ), pDriver->GetName().c_str(), vrDriverID.c_str(), pDriver->GetError().c_str() );
+ return MIstatus::failure;
+ }
+
+ MapPairDriverIdToDriver_t pr( vrDriverID, pDriver );
+ m_mapDriverIdToDriver.insert( pr );
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Query the Driver Manager to see if *this manager has the driver already
+// registered.
+// Type: Method.
+// Args: vrDriver - (R) The driver to query.
+// Return: True - registered.
+// False - not registered.
+// Throws: None.
+//--
+bool CMIDriverMgr::HaveDriverAlready( const IDriver & vrDriver ) const
+{
+ MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
+ while( it != m_mapDriverIdToDriver.end() )
+ {
+ const IDriver * pDrvr = (*it).second;
+ if( pDrvr == &vrDriver )
+ return true;
+
+ // Next
+ ++it;
+ }
+
+ return false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Unregister a driver from the Driver Manager. Call the SetUseThisDriverToDoWork()
+// function to define another driver to do work if the one being unregistered did
+// the work previously.
+// Type: Method.
+// Args: vrDriver - (R) The driver to unregister.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriverMgr::UnregisterDriver( const IDriver & vrDriver )
+{
+ const IDriver * pDrvr = nullptr;
+ MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
+ while( it != m_mapDriverIdToDriver.end() )
+ {
+ pDrvr = (*it).second;
+ if( pDrvr == &vrDriver )
+ break;
+
+ // Next
+ ++it;
+ }
+ m_mapDriverIdToDriver.erase( it );
+
+ if( m_pDriverCurrent == pDrvr )
+ m_pDriverCurrent = nullptr;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Specify the driver to do work. The Driver Manager drives this driver. Any
+// previous driver doing work is not called anymore (so be sure the previous
+// driver is in a tidy state before stopping it working).
+// Type: Method.
+// Args: vrADriver - (R) A lldb::SBBroadcaster/IDriver derived object.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriverMgr::SetUseThisDriverToDoWork( const IDriver & vrADriver )
+{
+ m_pDriverCurrent = const_cast< IDriver * >( &vrADriver );
+
+ const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_SAY_DRIVER_USING ), m_pDriverCurrent->GetName().c_str() ) );
+ m_pLog->Write( msg, CMICmnLog::eLogVerbosity_Log );
+
+ m_bInMi2Mode = m_pDriverCurrent->GetDriverIsGDBMICompatibleDriver();
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Ask *this manager which driver is currently doing the work.
+// Type: Method.
+// Args: None.
+// Return: IDriver * - Pointer to a driver, NULL if there is no current working driver.
+// Throws: None.
+//--
+CMIDriverMgr::IDriver * CMIDriverMgr::GetUseThisDriverToDoWork( void ) const
+{
+ return m_pDriverCurrent;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Call this function puts *this driver to work.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriverMgr::DriverMainLoop( void )
+{
+ if( m_pDriverCurrent != nullptr )
+ {
+ if( !m_pDriverCurrent->DoMainLoop() )
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_MAINLOOP ), m_pDriverCurrent->GetError().c_str() ) );
+ CMICmnStreamStdout::Instance().Write( errMsg, true );
+ return MIstatus::failure;
+ }
+ }
+ else
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_CURRENT_NOT_SET ) ) );
+ CMICmnStreamStdout::Instance().Write( errMsg, true );
+ return MIstatus::failure;
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Call *this driver to resize the console window.
+// Type: Method.
+// Args: vWindowSizeWsCol - (R) New window column size.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+void CMIDriverMgr::DriverResizeWindow( const uint32_t vWindowSizeWsCol )
+{
+ if( m_pDriverCurrent != nullptr )
+ return m_pDriverCurrent->DoResizeWindow( vWindowSizeWsCol );
+ else
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_CURRENT_NOT_SET ) ) );
+ CMICmnStreamStdout::Instance().Write( errMsg, true );
+ }
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Get the current driver to validate executable command line arguments.
+// Type: Method.
+// Args: argc - (R) An integer that contains the count of arguments that follow in
+// argv. The argc parameter is always greater than or equal to 1.
+// argv - (R) An array of null-terminated strings representing command-line
+// arguments entered by the user of the program. By convention,
+// argv[0] is the command with which the program is invoked.
+// vpStdOut - (R) Point to a standard output stream.
+// vwbExiting - (W) True = *this want to exit, false = continue to work.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIDriverMgr::DriverParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting )
+{
+ if( m_pDriverCurrent == nullptr )
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_CURRENT_NOT_SET ) ) );
+ CMICmnStreamStdout::Instance().Write( errMsg, true );
+ return MIstatus::failure;
+ }
+
+ const lldb::SBError error( m_pDriverCurrent->DoParseArgs( argc, argv, vpStdOut, vwbExiting ) );
+ bool bOk = !error.Fail();
+ if( !bOk )
+ {
+ CMIUtilString errMsg;
+ const MIchar * pErrorCstr = error.GetCString();
+ if( pErrorCstr != nullptr )
+ errMsg = CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_PARSE_ARGS ), m_pDriverCurrent->GetName().c_str(), pErrorCstr );
+ else
+ errMsg = CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_PARSE_ARGS_UNKNOWN ), m_pDriverCurrent->GetName().c_str() );
+
+ bOk = CMICmnStreamStdout::Instance().Write( errMsg, true );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the current driver's last error condition.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Text description.
+// Throws: None.
+//--
+CMIUtilString CMIDriverMgr::DriverGetError( void ) const
+{
+ if( m_pDriverCurrent != nullptr )
+ return m_pDriverCurrent->GetError();
+ else
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_CURRENT_NOT_SET ) ) );
+ CMICmnStreamStdout::Instance().Write( errMsg, true );
+ }
+
+ return CMIUtilString();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the current driver's name.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Driver name.
+// Empty string = no current working driver specified.
+// Throws: None.
+//--
+CMIUtilString CMIDriverMgr::DriverGetName( void ) const
+{
+ if( m_pDriverCurrent != nullptr )
+ return m_pDriverCurrent->GetName();
+ else
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_CURRENT_NOT_SET ) ) );
+ CMICmnStreamStdout::Instance().Write( errMsg, true );
+ }
+
+ return CMIUtilString();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the current driver's debugger object.
+// Type: Method.
+// Args: None.
+// Return: lldb::SBDebugger * - Ptr to driver's debugger object.
+// - NULL = no current working driver specified.
+// Throws: None.
+//--
+lldb::SBDebugger * CMIDriverMgr::DriverGetTheDebugger( void )
+{
+ lldb::SBDebugger * pDebugger = nullptr;
+ if( m_pDriverCurrent != nullptr )
+ pDebugger = &m_pDriverCurrent->GetTheDebugger();
+ else
+ {
+ const CMIUtilString errMsg( CMIUtilString::Format( MIRSRC( IDS_DRIVER_ERR_CURRENT_NOT_SET ) ) );
+ CMICmnStreamStdout::Instance().Write( errMsg, true );
+ }
+
+ return pDebugger;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Check the arguments given on the command line. The main purpose of this
+// function is to check for the presence of the --interpreter option. Having
+// this option present tells *this manager to set the CMIDriver to do work. If
+// not use the LLDB driver. The following are options that are only handled by
+// the CMIDriverMgr are:
+// --help or -h
+// --interpreter
+// --version
+// --versionLong
+// --noLog
+// --executable
+// The above arguments are not handled by any driver object except for --executable.
+// The options --interpreter and --executable in code act very similar. The
+// --executable is necessary to differentiate whither the MI Driver is being using
+// by a client i.e. Eclipse or from the command line. Eclipse issues the option
+// --interpreter and also passes additional arguments which can be interpreted as an
+// executable if called from the command line. Using --executable tells the MI
+// Driver is being called the command line and that the executable argument is indeed
+// a specified executable an so actions commands to set up the executable for a
+// debug session. Using --interpreter on the commnd line does not action additional
+// commands to initialise a debug session and so be able to launch the process.
+// Type: Method.
+// Args: argc - (R) An integer that contains the count of arguments that follow in
+// argv. The argc parameter is always greater than or equal to 1.
+// argv - (R) An array of null-terminated strings representing command-line
+// arguments entered by the user of the program. By convention,
+// argv[0] is the command with which the program is invoked.
+// vwbExiting - (W) True = *this want to exit, Reasons: help, invalid arg(s),
+// version information only.
+// False = Continue to work, start debugger i.e. Command
+// interpreter.
+// Return: lldb::SBError - LLDB current error status.
+// Throws: None.
+//--
+bool CMIDriverMgr::ParseArgs( const int argc, const char * argv[], bool & vwbExiting )
+{
+ bool bOk = MIstatus::success;
+
+ vwbExiting = false;
+
+ // Print MI application path to the Log file
+ const CMIUtilString appPath( CMIUtilString::Format( MIRSRC( IDS_MI_APP_FILEPATHNAME ), argv[ 0 ] ) );
+ bOk = m_pLog->Write( appPath, CMICmnLog::eLogVerbosity_Log );
+
+ // Print application arguments to the Log file
+ const bool bHaveArgs( argc >= 2 );
+ CMIUtilString strArgs( MIRSRC( IDS_MI_APP_ARGS ) );
+ if( !bHaveArgs )
+ {
+ strArgs += MIRSRC( IDS_WORD_NONE );
+ bOk = bOk && m_pLog->Write( strArgs, CMICmnLog::eLogVerbosity_Log );
+ }
+ else
+ {
+ for( MIint i = 1; i < argc; i++ )
+ {
+ strArgs += CMIUtilString::Format( "%d:'%s' ", i, argv[ i ] );
+ }
+ bOk = bOk && m_pLog->Write( strArgs, CMICmnLog::eLogVerbosity_Log );
+ }
+
+ // Look for the command line options
+ bool bHaveArgInterpret = false;
+ bool bHaveArgVersion = false;
+ bool bHaveArgVersionLong = false;
+ bool bHaveArgNoLog = false;
+ bool bHaveArgHelp = false;
+
+ // Hardcode the use of the MI driver
+#if MICONFIG_DEFAULT_TO_MI_DRIVER
+ bHaveArgInterpret = true;
+#endif // MICONFIG_DEFAULT_TO_MI_DRIVER
+
+ if( bHaveArgs )
+ {
+ // CODETAG_MIDRIVE_CMD_LINE_ARG_HANDLING
+ for( MIint i = 1; i < argc; i++ )
+ {
+ // *** Add args to help in GetHelpOnCmdLineArgOptions() ***
+ const CMIUtilString strArg( argv[ i ] );
+
+ // Argument "--executable" is also check for in CMIDriver::ParseArgs()
+ if( (0 == strArg.compare( "--interpreter" )) || // Given by the client such as Eclipse
+ (0 == strArg.compare( "--executable" )) ) // Used to specify that there is executable argument also on the command line
+ { // See fn description.
+ bHaveArgInterpret = true;
+ }
+ if( 0 == strArg.compare( "--version" ) )
+ {
+ bHaveArgVersion = true;
+ }
+ if( 0 == strArg.compare( "--versionLong" ) )
+ {
+ bHaveArgVersionLong = true;
+ }
+ if( 0 == strArg.compare( "--noLog" ) )
+ {
+ bHaveArgNoLog = true;
+ }
+ if( (0 == strArg.compare( "--help" )) || (0 == strArg.compare( "-h" )) )
+ {
+ bHaveArgHelp = true;
+ }
+ }
+ }
+
+ if( bHaveArgNoLog )
+ {
+ CMICmnLog::Instance().SetEnabled( false );
+ }
+
+ // Todo: Remove this output when MI is finished. It is temporary to persuade Ecllipse plugin to work.
+ // Eclipse reads this literally and will not work unless it gets this exact version text.
+ // Handle --version option (ignore the --interpreter option if present)
+ if( bHaveArgVersion )
+ {
+ vwbExiting = true;
+ bOk = bOk && CMICmnStreamStdout::Instance().WriteMIResponse( MIRSRC( IDE_MI_VERSION_GDB ) );
+ return bOk;
+ }
+
+ // Todo: Make this the --version when the the above --version version is removed
+ // Handle --versionlong option (ignore the --interpreter option if present)
+ if( bHaveArgVersionLong )
+ {
+ vwbExiting = true;
+ bOk = bOk && CMICmnStreamStdout::Instance().WriteMIResponse( GetAppVersion() );
+ return bOk;
+ }
+
+ // Both '--help' and '--intepreter' means give help for MI only. Without
+ // '--interpreter' help the LLDB driver is working and so help is for that.
+ if( bHaveArgHelp && bHaveArgInterpret )
+ {
+ vwbExiting = true;
+ bOk = bOk && CMICmnStreamStdout::Instance().WriteMIResponse( GetHelpOnCmdLineArgOptions() );
+ return bOk;
+ }
+
+ // This makes the assumption that there is at least one MI compatible
+ // driver registered and one LLDB driver registerd and the CMIDriver
+ // is the first one found.
+ // ToDo: Implement a better solution that handle any order, any number
+ // of drivers. Or this 'feature' may be removed if deemed not required.
+ IDriver * pLldbDriver = GetFirstNonMIDriver();
+ IDriver * pMi2Driver = GetFirstMIDriver();
+ if( bHaveArgInterpret && (pMi2Driver != nullptr) )
+ bOk = bOk && SetUseThisDriverToDoWork( *pMi2Driver );
+ else if( pLldbDriver != nullptr )
+ bOk = bOk && SetUseThisDriverToDoWork( *pLldbDriver );
+ else
+ {
+ if( bOk )
+ {
+ vwbExiting = true;
+ const CMIUtilString msg( MIRSRC( IDS_DRIVER_ERR_NON_REGISTERED ) );
+ bOk = bOk && CMICmnStreamStdout::Instance().WriteMIResponse( msg );
+ }
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Return formatted application version and name information.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Text data.
+// Throws: None.
+//--
+CMIUtilString CMIDriverMgr::GetAppVersion( void ) const
+{
+ const CMIUtilString strProj( MIRSRC( IDS_PROJNAME ) );
+ const CMIUtilString strVsn( CMIDriver::Instance().GetVersionDescription() );
+ const CMIUtilString strGdb( MIRSRC( IDE_MI_VERSION_GDB ) );
+ const CMIUtilString strVrsnInfo( CMIUtilString::Format( "%s\n%s\n%s", strProj.c_str(), strVsn.c_str(), strGdb.c_str() ) );
+
+ return strVrsnInfo;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Return formatted help information on all the MI command line options.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Text data.
+// Throws: None.
+//--
+CMIUtilString CMIDriverMgr::GetHelpOnCmdLineArgOptions( void ) const
+{
+ const CMIUtilString pHelp[] =
+ {
+ MIRSRC( IDE_MI_APP_DESCRIPTION ),
+ MIRSRC( IDE_MI_APP_INFORMATION ),
+ MIRSRC( IDE_MI_APP_ARG_USAGE ),
+ MIRSRC( IDE_MI_APP_ARG_HELP ),
+ MIRSRC( IDE_MI_APP_ARG_VERSION ),
+ MIRSRC( IDE_MI_APP_ARG_VERSION_LONG ),
+ MIRSRC( IDE_MI_APP_ARG_INTERPRETER ),
+ MIRSRC( IDE_MI_APP_ARG_EXECUTEABLE ),
+ CMIUtilString::Format( MIRSRC( IDE_MI_APP_ARG_NO_APP_LOG ), CMICmnLogMediumFile::Instance().GetFileName().c_str() ),
+ MIRSRC( IDE_MI_APP_ARG_EXECUTABLE ),
+ MIRSRC( IDS_CMD_QUIT_HELP ),
+ MIRSRC( IDE_MI_APP_ARG_EXAMPLE )
+ };
+ const MIuint nHelpItems = sizeof pHelp / sizeof pHelp[ 0 ];
+ CMIUtilString strHelp;
+ for( MIuint i = 0; i < nHelpItems; i++ )
+ {
+ strHelp += pHelp[ i ];
+ strHelp += "\n\n";
+ }
+
+ return strHelp;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Search the registered drivers and return the first driver which says it is
+// GDB/MI compatible i.e. the CMIDriver class.
+// Type: Method.
+// Args: None.
+// Return: IDriver * - Ptr to driver, NULL = no driver found.
+// Throws: None.
+//--
+CMIDriverMgr::IDriver * CMIDriverMgr::GetFirstMIDriver( void ) const
+{
+ IDriver * pDriver = nullptr;
+ MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
+ while( it != m_mapDriverIdToDriver.end() )
+ {
+ const CMIUtilString & rDrvId = (*it).first; MIunused( rDrvId );
+ IDriver * pDvr = (*it).second;
+ if( pDvr->GetDriverIsGDBMICompatibleDriver() )
+ {
+ pDriver = pDvr;
+ break;
+ }
+
+ // Next
+ ++it;
+ }
+
+ return pDriver;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Search the registered drivers and return the first driver which says it is
+// not GDB/MI compatible i.e. the LLDB Driver class.
+// Type: Method.
+// Args: None.
+// Return: IDriver * - Ptr to driver, NULL = no driver found.
+// Throws: None.
+//--
+CMIDriverMgr::IDriver * CMIDriverMgr::GetFirstNonMIDriver( void ) const
+{
+ IDriver * pDriver = nullptr;
+ MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
+ while( it != m_mapDriverIdToDriver.end() )
+ {
+ const CMIUtilString & rDrvId = (*it).first; MIunused( rDrvId );
+ IDriver * pDvr = (*it).second;
+ if( !pDvr->GetDriverIsGDBMICompatibleDriver() )
+ {
+ pDriver = pDvr;
+ break;
+ }
+
+ // Next
+ ++it;
+ }
+
+ return pDriver;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Search the registered drivers and return driver with the specified ID.
+// Type: Method.
+// Args: vrDriverId - (R) ID of a driver.
+// Return: IDriver * - Ptr to driver, NULL = no driver found.
+// Throws: None.
+//--
+CMIDriverMgr::IDriver * CMIDriverMgr::GetDriver( const CMIUtilString & vrDriverId ) const
+{
+ MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.find( vrDriverId );
+ if( it == m_mapDriverIdToDriver.end() )
+ return nullptr;
+
+ IDriver * pDriver = (*it).second;
+
+ return pDriver;
+}
+
diff --git a/tools/lldb-mi/MIDriverMgr.h b/tools/lldb-mi/MIDriverMgr.h
new file mode 100644
index 000000000000..438d184895b1
--- /dev/null
+++ b/tools/lldb-mi/MIDriverMgr.h
@@ -0,0 +1,138 @@
+//===-- MIDriverMgr.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIDriverMgr.h
+//
+// Overview: CMIImplCmn interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadme.txt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <map>
+#include <lldb/API/SBDebugger.h>
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MIUtilString.h"
+#include "MICmnLog.h"
+#include "MIUtilSingletonBase.h"
+
+//++ ============================================================================
+// Details: MI Driver Manager. Register lldb::SBBroadcaster derived Driver type
+// objects with *this manager. The manager does not own driver objects
+// registered with it and so will not delete when this manager is
+// shutdown. The Driver flagged as "use this one" will be set as current
+// driver and will be the one that is used. Other drivers are not
+// operated. A Driver can call another Driver should it not handle a
+// command.
+// It also initializes other resources as part it's setup such as the
+// Logger and Resources objects (explicit indicate *this object requires
+// those objects (modules/components) to support it's own functionality).
+// The Driver manager is the first object instantiated as part of the
+// MI code base. It is also the first thing to interpret the command
+// line arguments passed to the executeable. Bases on options it
+// understands the manage will set up the appropriate driver or give
+// help information. Other options are passed on to the driver chosen
+// to do work.
+// Each driver instance (the CMIDriver, LLDB::Driver) has its own
+// LLDB::SBDebugger.
+// Singleton class.
+// Gotchas: None.
+// Authors: Illya Rudkin 28/02/2014.
+// Changes: None.
+//--
+class CMIDriverMgr
+: public CMICmnBase
+, public MI::ISingleton< CMIDriverMgr >
+{
+ friend MI::ISingleton< CMIDriverMgr >;
+
+// Class:
+public:
+ //++
+ // Description: Driver deriver objects need this interface to work with
+ // *this manager.
+ //--
+ class IDriver
+ {
+ public:
+ virtual bool DoInitialize( void ) = 0;
+ virtual bool DoShutdown( void ) = 0;
+ virtual bool DoMainLoop( void ) = 0;
+ virtual void DoResizeWindow( const uint32_t vWindowSizeWsCol ) = 0;
+ virtual lldb::SBError DoParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting ) = 0;
+ virtual CMIUtilString GetError( void ) const = 0;
+ virtual const CMIUtilString & GetName( void ) const = 0;
+ virtual lldb::SBDebugger & GetTheDebugger( void ) = 0;
+ virtual bool GetDriverIsGDBMICompatibleDriver( void ) const = 0;
+ virtual bool SetId( const CMIUtilString & vId ) = 0;
+ virtual const CMIUtilString & GetId( void ) const = 0;
+
+ // Not part of the interface, ignore
+ /* dtor */ virtual ~IDriver( void ) {}
+ };
+
+// Methods:
+public:
+ // MI system
+ bool Initialize( void );
+ bool Shutdown( void );
+ //
+ CMIUtilString GetAppVersion( void ) const;
+ bool RegisterDriver( const IDriver & vrADriver, const CMIUtilString & vrDriverID );
+ bool UnregisterDriver( const IDriver & vrADriver );
+ bool SetUseThisDriverToDoWork( const IDriver & vrADriver ); // Specify working main driver
+ IDriver * GetUseThisDriverToDoWork( void ) const;
+ bool ParseArgs( const int argc, const char * argv[], bool & vwbExiting );
+ IDriver * GetDriver( const CMIUtilString & vrDriverId ) const;
+ //
+ // MI Proxy fn to current specified working driver
+ bool DriverMainLoop( void );
+ void DriverResizeWindow( const uint32_t vWindowSizeWsCol );
+ bool DriverParseArgs( const int argc, const char * argv[], FILE * vpStdOut, bool & vwbExiting );
+ CMIUtilString DriverGetError( void ) const;
+ CMIUtilString DriverGetName( void ) const;
+ lldb::SBDebugger * DriverGetTheDebugger( void );
+
+// Typedef:
+private:
+ typedef std::map< CMIUtilString, IDriver * > MapDriverIdToDriver_t;
+ typedef std::pair< CMIUtilString, IDriver * > MapPairDriverIdToDriver_t;
+
+// Methods:
+private:
+ /* ctor */ CMIDriverMgr( void );
+ /* ctor */ CMIDriverMgr( const CMIDriverMgr & );
+ void operator=( const CMIDriverMgr & );
+ //
+ bool HaveDriverAlready( const IDriver & vrMedium ) const;
+ bool UnregisterDriverAll( void );
+ IDriver * GetFirstMIDriver( void ) const;
+ IDriver * GetFirstNonMIDriver( void ) const;
+ CMIUtilString GetHelpOnCmdLineArgOptions( void ) const;
+
+// Overridden:
+private:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMIDriverMgr( void );
+
+// Attributes:
+private:
+ MapDriverIdToDriver_t m_mapDriverIdToDriver;
+ IDriver * m_pDriverCurrent; // This driver is used by this manager to do work. It is the main driver.
+ bool m_bInMi2Mode; // True = --interpreter entered on the cmd line, false = operate LLDB driver (non GDB)
+};
diff --git a/tools/lldb-mi/MIReadMe.txt b/tools/lldb-mi/MIReadMe.txt
new file mode 100644
index 000000000000..fbd3b2d364f6
--- /dev/null
+++ b/tools/lldb-mi/MIReadMe.txt
@@ -0,0 +1,261 @@
+========================================================================
+ The MI Driver - LLDB Machine Interface V2 (MI) Project Overview
+ 24/07/2014
+========================================================================
+
+The MI Driver is a stand alone executable that either be used via a
+client i.e. Eclipse or directly from the command line.
+
+All the files in this directory are required to build the MI executable.
+The executable is intended to compile and work on the following platforms:
+
+ Windows (Vista or newer) (Compiler: Visual C++ 12)
+ LINUX (Compiler: gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1)
+ OSX (Not tested)
+
+THe MI Driver has two modes of operation; LLDB and MI. The MI Driver (CMIDriver)
+which operates the MI mode is a driver in its own right to work alongside
+the LLDB driver (driver .h/.cpp). Only one is operatational at a time depending
+on the options entered on the command line. The MI Driver reads MI inputs and
+outputs MI responses to be interpreted by a client i.e. Eclipse.
+Should the MI Driver not understand an instruction it could be passed to the
+LLDB driver for interpretation (MI Driver build configuration dependant). Should
+the LLDB driver mode be chosen then it the MI Driver will behave as the normal
+LLDB driver.
+
+For help information on using the MI driver type at the command line:
+
+ lldb-mi --interpreter --help
+
+A blog about the MI Driver is available on CodePlay's website
+http://www.codeplay.com/portal/.
+
+The MI Driver produces a MILog.txt file which records the actions of the MI
+Driver when in the MI mode only.
+
+Note any command or text sent to the MI Driver in MI mode that is not a command
+registered in the MI Driver's Command Factory will be rejected given an error.
+
+The MILogfile.txt keeps a history of the MI Driver's activity for one session
+only. It is used to aid the debugging of the MI Driver in MI mode only. As well
+as recorded commands that are recognised by the MI Driver it also gives warnings
+about command's which do not support certain argument or options.
+
+All the files prefix with MI are specifically for the MI driver code only.
+Non prefixed code is the original LLDB driver which has been left untouched
+as much as possible. This allows the LLDB driver code to develop
+independently and make future integration more straight forward.
+
+File MIDriverMain.cpp contains the executables main() function and some
+common global functions common to the two drivers.
+
+=========================================================================
+Current limitations:
+1. Commands implemented likely not to have all their arguments supported
+2. The MI Driver has only been tested with Eclipse Juno with an in-house
+ plugin
+3. Local target has been implemented but not tested
+4. The MI Driver has been designed primarily to work in a 'remote-target'
+ mode only. The MI Driver does not currently except arguments beyond
+ those described above.
+5. The MI Driver does not accept as arguments an executable to create a
+ target instance.
+6. Not all MI commands have been implemented. See section MI Driver
+ commands for those that have been fully or partially implemented (not
+ indicated - see command class).
+7. Not necessarily a limitation but the MI Driver is used with Codeplay's
+ own Eclipse plugin (not supplied) which has allowed more control over
+ the interaction with the MI Driver between Eclipse.
+
+=========================================================================
+Versions:
+1.0.0.1 First version from scratch 28/1/2014 to 28/3/2014.
+ MI working alpha. MI framework not complete.
+1.0.0.2 First deliverable to client 7/3/2014.
+ MI working beta. MI framework not complete.
+1.0.0.3 Code refactor tidy. Release to community for evaluation
+ 7/5/2014.
+ MI working beta - code refactored and tidied. MI framework
+ complete. Just missing commands (which may still require
+ changes).
+1.0.0.4 Post release to community for evaluation 7/5/2014.
+ 1. MI command token now optional
+ 2. MI command token is now fixed length
+ 3. New commands added see section "MI commands implemented are:"
+ 4. Able to debug a local target as well as remote target
+ 5. MI Driver now sends to the client "(gdb)" + '\n' on
+ initialising
+ 6. Improve coverage of parsing and fix command argument parsing
+ 7. Fix bug with stdin thinking there was no input when there was which
+ caused communication between the client and the MI Driver to halt
+ due to internal buffering, we now keep track of it ourself.
+ 8. Code comment fixes and additions. Code style fixes.
+ 9. MI Driver now on receiving Ctrl-C (SIGINT) when the client pauses
+ an inferior program does not quit but continues operating.
+ 10.Fix commands "var-update", "var-evaluate-expression" to which did
+ not send back information to correctly update arrays and structures.
+ 11.Commands "Not implemented" are now not registered to the command
+ factory except for GDB command "thread". Commands not registered
+ with the command factory produce MI error message "...not in
+ Command Factory". (Removed from command section in this readme.txt)
+1.0.0.5 Second deliverable to client 16/6/2014.
+1.0.0.6 Post release of second deliverable to client 16/6/2014.
+ Released to the community 24/6/2014.
+ 1. The MI Driver has a new option --noLog. If present the MI Driver
+ does not output progress or status messages to it's log file.
+ 2. Moved OS specific handling of the stdin stream to their own class
+ implementations so any changes to one handler will not affect
+ another OS's handler.
+ 3. The session data/information map for sharing data between commands
+ now uses a variant object which enables objects of different types
+ to be stored instead of previously just text information.
+ 4. Debug session var object create, update and retrieve efficiency
+ improved by using a map type container.
+ 5. Re-enable the MI Driver's command line option --interpreter (see
+ --help). Up until now it was implementented but not enforced, it
+ was always the MI Driver interpreter.
+ 6. Re-enable the compilation of the original LLDB driver code into
+ the MI Driver's code. See MICmnConfig.h for build configuration.
+1.0.0.7 Post release to community. Delivered to client 30/6/2014.
+ 1. Fix MI Driver's output of "(gdb)" appearing when running in LLDB
+ mode (no --interpreter argument)'
+ 2. Fix command "interpret-exec" to allow commands to be entered
+ directly in the IDE console.
+1.0.0.8 Post release to client. Delivered to client 29/07/2014
+ 1. Fix command "break-insert" argument -f not accepting file paths
+ as a string. Looked like the MI Driver was not accepting LINUX
+ style file paths in the Windows version and vice versa.
+ 2. Fix command "stack-list-arguments" handling only the current
+ stack frame. Eclipse now shows variables for all frames.
+ 3. Fix and improve MI response for sending back information on
+ stack local variables, stack arguments and stack frame selection.
+ 4. Fix recursive crash when asking to gather information on link
+ lists.
+ 5. Fix MI Driver's Log date and time field.
+ 6. Fix MI response return from event 'StopReason' and 'Breakpoint-
+ hit'.
+ 7. Fix command "environment-cd" to handle paths with spaces in the
+ path.
+ 8. Fix not displaying backtrace (stack) variable information when
+ choosing frames other than the current frame.
+ 9. Fix command "data-evaluate-expression" to be able to handle
+ valid SBValue objects but have no value object name. Fix same
+ command to handle expressions surround by string format inserted
+ quotes.
+ 10.Fix command "break-insert" to handle file location that is
+ surrounded by quotes.
+ 11.For commands "var-create" and "data-evaluate-expression" improve
+ variable type handling for quoted expressions.
+ 12.Implement command "inferior-tty-set". It just responds with
+ "^Done".
+ 13.Improve the MI Driver's help description.
+ 14.Fix file name paths that contained '.', '-' and '_' in the path
+ as being treated as invalid.
+ 15.Fix trying to interpret escapse character text as an errorous
+ command.
+1.0.0.9 Post release to client.
+
+=========================================================================
+MI Driver Commands
+MI commands below are written to work for Eclipse Juno 7.4. If may be
+one are more commands required by other IDEs are missing or do not
+support all arguments or options. Additionally some commands may handle
+additional arguments or options not documented here
+https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Data-Manipulation.html#GDB_002fMI-Data-Manipulation.
+The implemented commands are:
+CMICmdCmdBreakAfter
+CMICmdCmdBreakCondition
+CMICmdCmdBreakDelete
+CMICmdCmdBreakDisable
+CMICmdCmdBreakEnable
+CMICmdCmdBreakInsert
+CMICmdCmdDataEvaluateExpression
+CMICmdCmdDataDisassemble
+CMICmdCmdDataListRegisterChanged
+CMICmdCmdDataListRegisterNames
+CMICmdCmdDataListRegisterValues
+CMICmdCmdDataReadMemory
+CMICmdCmdDataReadMemoryBytes
+CMICmdCmdDataWriteMemory
+CMICmdCmdEnablePrettyPrinting
+CMICmdCmdEnvironmentCd
+CMICmdCmdExecContinue
+CMICmdCmdExecFinish
+CMICmdCmdExecInterrupt
+CMICmdCmdExecNext
+CMICmdCmdExecNextInstruction
+CMICmdCmdExecRun
+CMICmdCmdExecStep
+CMICmdCmdExecStepInstruction
+CMICmdCmdFileExecAndSymbols
+CMICmdCmdGdbExit
+CMICmdCmdGdbInfo
+CMICmdCmdGdbSet
+CMICmdCmdGdbSet - solib-search-path option
+CMICmdCmdInferiorTtySet (not functionally implemented)
+CMICmdCmdInterpreterExec
+CMICmdCmdListThreadGroups
+CMICmdCmdSource
+CMICmdCmdStackInfoDepth
+CMICmdCmdStackListArguments
+CMICmdCmdStackListFrames
+CMICmdCmdStackListLocals
+CMICmdCmdSupportInfoMiCmdQuery
+CMICmdCmdSupportListFeatures
+CMICmdCmdTargetSelect
+CMICmdCmdThread
+CMICmdCmdThreadInfo
+CMICmdCmdTraceStatus (not functionally implemented)
+CMICmdCmdVarAssign
+CMICmdCmdVarCreate
+CMICmdCmdVarDelete
+CMICmdCmdVarEvaluateExpression
+CMICmdCmdVarInfoPathExpression
+CMICmdCmdVarListChildren
+CMICmdCmdVarSetFormat
+CMICmdCmdVarShowAttributes
+CMICmdCmdVarUpdate
+
+=========================================================================
+The MI Driver build configuration:
+MICmnConfig.h defines various preprocessor build options i.e. enable
+LLDB driver fall through (Driver.h/.cpp) should MI Driver not recognise a
+command (option not fully implemented - may be removed in the future).
+
+=========================================================================
+Code standard, documentation and code style scope:
+The coding style and coding documentation scope covers all MI prefixed
+files and where MI code is implemented in the LLDB driver files. Should
+you wish to make improvements or fixes to the MI code (which is encouraged)
+please DO comment your code in the style already applied. The same applies
+to the coding style. Class names should also follow this lead and ideally
+should be one class per file (.h/.cpp). Class interface files (.h) should
+not contain any implementation code unless there is a performance issue or
+templated functions. You get the idea, look around the existing code and
+follow by example :)
+
+Where code comment or documentation is wrong or can be improved to help
+others then it is strongly encouraged you DO improve the documentation.
+
+=========================================================================
+MI Driver license:
+The MI Driver code is under the University of Illinois Open Source License
+agreement. Submitted by Codeplay Ltd UK.
+
+Source code found at: llvm/tools/lldb/tools/lldb-mi.
+
+=========================================================================
+The MI Driver uses the following libraries:
+Standard Template library
+ Thread
+ Containers
+ String
+ File
+ Time
+LLDB public API
+OS specific
+ OS error reporting windows
+ OS error handling OSX (not implemented)
+ OS error handling LINUX (not implemented)
+
+
diff --git a/tools/lldb-mi/MIUtilDateTimeStd.cpp b/tools/lldb-mi/MIUtilDateTimeStd.cpp
new file mode 100644
index 000000000000..9938deb131cc
--- /dev/null
+++ b/tools/lldb-mi/MIUtilDateTimeStd.cpp
@@ -0,0 +1,84 @@
+//===-- MIUtilDateTimeStd.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilDateTimeStd.cpp
+//
+// Overview: CMIUtilDateTimeStd implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MIUtilDateTimeStd.h"
+#include "MICmnResources.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilDateTimeStd constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilDateTimeStd::CMIUtilDateTimeStd( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilDateTimeStd destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilDateTimeStd::~CMIUtilDateTimeStd( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve system local current date. Format is MM/DD/YYYY.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Text description.
+// Throws: None.
+//--
+CMIUtilString CMIUtilDateTimeStd::GetDate( void )
+{
+ CMIUtilString strDate( MIRSRC( IDS_WORD_INVALIDBRKTS ) );
+
+ std::time( &m_rawTime );
+ const std::tm * pTi = std::localtime( &m_rawTime );
+ if( std::strftime( &m_pScratch[ 0 ], sizeof( m_pScratch ), "%d/%m/%y", pTi ) > 0 )
+ strDate = m_pScratch;
+
+ return strDate;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve system local current time. Format is HH:MM:SS 24 hour clock.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Text description.
+// Throws: None.
+//--
+CMIUtilString CMIUtilDateTimeStd::GetTime( void )
+{
+ std::time( &m_rawTime );
+ const std::tm * pTi = std::localtime( &m_rawTime );
+ const CMIUtilString seconds( CMIUtilString::Format( "%d", pTi->tm_sec ) );
+ const CMIUtilString zero( (seconds.length() == 1) ? "0" : "" );
+ const CMIUtilString strTime( CMIUtilString::Format( "%d:%d:%s%s", pTi->tm_hour, pTi->tm_min, zero.c_str(), seconds.c_str() ) );
+
+ return strTime;
+}
+
diff --git a/tools/lldb-mi/MIUtilDateTimeStd.h b/tools/lldb-mi/MIUtilDateTimeStd.h
new file mode 100644
index 000000000000..da857d6358ee
--- /dev/null
+++ b/tools/lldb-mi/MIUtilDateTimeStd.h
@@ -0,0 +1,55 @@
+//===-- MIUtilDateTimeStd.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilDateTimeStd.h
+//
+// Overview: CMIUtilDateTimeStd interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers
+#include <ctime>
+
+// In-house headers:
+#include "MIUtilString.h"
+
+//++ ============================================================================
+// Details: MI common code utility class. Used to retrieve system local date
+// time.
+// Gotchas: None.
+// Authors: Illya Rudkin 16/07/2014.
+// Changes: None.
+//--
+class CMIUtilDateTimeStd
+{
+// Methods:
+public:
+ /* ctor */ CMIUtilDateTimeStd( void );
+
+ CMIUtilString GetDate( void );
+ CMIUtilString GetTime( void );
+
+// Overrideable:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMIUtilDateTimeStd( void );
+
+// Attributes:
+private:
+ std::time_t m_rawTime;
+ MIchar m_pScratch[ 16 ];
+};
diff --git a/tools/lldb-mi/MIUtilDebug.cpp b/tools/lldb-mi/MIUtilDebug.cpp
new file mode 100644
index 000000000000..754920880ec4
--- /dev/null
+++ b/tools/lldb-mi/MIUtilDebug.cpp
@@ -0,0 +1,128 @@
+//===-- MIUtilDebug.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilDebug.h
+//
+// Overview: Terminal setting termios functions.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third party headers:
+#ifdef _WIN32
+#include <Windows.h>
+#endif
+
+// In-house headers:
+#include "MIUtilDebug.h"
+#include "MIDriver.h"
+#include "MICmnLog.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilDebug constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilDebug::CMIUtilDebug( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilDebug destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilDebug::~CMIUtilDebug( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Show a dialog to the process/application halts. It gives the opportunity to
+// attach a debugger.
+// Type: Static method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMIUtilDebug::ShowDlgWaitForDbgAttach( void )
+{
+ const CMIUtilString strCaption( CMIDriver::Instance().GetAppNameShort() );
+#ifdef _WIN32
+ ::MessageBoxA( NULL, "Attach your debugger now", strCaption.c_str(), MB_OK );
+#else
+ // ToDo: Implement other platform version of an Ok to continue dialog box
+#endif // _WIN32
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Temporarily stall the process/application to give the programmer the
+// opportunity to attach a debugger. How to use: Put a break in the programmer
+// where you want to visit, run the application then attach your debugger to the
+// application. Hit the debugger's pause button and the debugger should should
+// show this loop. Change the i variable value to break out of the loop and
+// visit your break point.
+// Type: Static method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMIUtilDebug::WaitForDbgAttachInfinteLoop( void )
+{
+ MIuint i = 0;
+ while( i == 0 )
+ {
+ const std::chrono::milliseconds time( 100 );
+ std::this_thread::sleep_for( time );
+ }
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+// Instantiations:
+CMICmnLog & CMIUtilDebugFnTrace::ms_rLog = CMICmnLog::Instance();
+MIuint CMIUtilDebugFnTrace::ms_fnDepthCnt = 0;
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilDebugFnTrace constructor.
+// Type: Method.
+// Args: vFnName - (R) The text to insert into the log.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilDebugFnTrace::CMIUtilDebugFnTrace( const CMIUtilString & vFnName )
+: m_strFnName( vFnName )
+{
+ const CMIUtilString txt( CMIUtilString::Format( "%d>%s", ++ms_fnDepthCnt, m_strFnName.c_str() ) );
+ ms_rLog.Write( txt, CMICmnLog::eLogVerbosity_FnTrace );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilDebugFnTrace destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilDebugFnTrace::~CMIUtilDebugFnTrace( void )
+{
+ const CMIUtilString txt( CMIUtilString::Format( "%d<%s", ms_fnDepthCnt--, m_strFnName.c_str() ) );
+ ms_rLog.Write( txt, CMICmnLog::eLogVerbosity_FnTrace );
+}
+
diff --git a/tools/lldb-mi/MIUtilDebug.h b/tools/lldb-mi/MIUtilDebug.h
new file mode 100644
index 000000000000..b163b05f5de5
--- /dev/null
+++ b/tools/lldb-mi/MIUtilDebug.h
@@ -0,0 +1,96 @@
+//===-- MIUtilDebug.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilDebug.h
+//
+// Overview: CMIUtilDebug interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+#define MI_USE_DEBUG_TRACE_FN // Undefine to compile out fn trace code
+
+// In-house headers:
+#include "MIUtilString.h"
+
+// Declarations:
+class CMICmnLog;
+
+//++ ============================================================================
+// Details: MI debugging aid utility class.
+// Gotchas: None.
+// Authors:
+// Changes: None.
+//--
+class CMIUtilDebug
+{
+// Statics:
+public:
+ static void ShowDlgWaitForDbgAttach( void );
+ static void WaitForDbgAttachInfinteLoop( void );
+
+// Methods:
+public:
+ /* ctor */ CMIUtilDebug( void );
+
+// Overrideable:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMIUtilDebug( void );
+};
+
+//++ ============================================================================
+// Details: MI debug utility class. Used to indicate the current function
+// depth in the call stack. It uses the CMIlCmnLog logger to output
+// the current fn trace information.
+// Use macro MI_TRACEFN( "Some fn name" ) and implement the scope of
+// the functions you wish to build up a trace off.
+// Use preprocessor definition MI_USE_DEBUG_TRACE_FN to turn off or on
+// tracing code.
+// Gotchas: None.
+// Authors: Illya Rudkin 07/03/2014.
+// Changes: None.
+//--
+class CMIUtilDebugFnTrace
+{
+// Methods:
+public:
+ /* ctor */ CMIUtilDebugFnTrace( const CMIUtilString & vFnName );
+
+// Overrideable:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMIUtilDebugFnTrace( void );
+
+// Attributes:
+private:
+ const CMIUtilString m_strFnName;
+
+ static CMICmnLog & ms_rLog;
+ static MIuint ms_fnDepthCnt; // Increment count as fn depth increases, decrement count as fn stack pops off
+};
+
+//++ ============================================================================
+// Details: Take the given text and send it to the server's Logger to output to the
+// trace file.
+// Type: Compile preprocess.
+// Args: x - (R) Message (may be seen by user).
+//--
+#ifdef MI_USE_DEBUG_TRACE_FN
+#define MI_TRACEFN( x ) CMIUtilDebugFnTrace __MITrace( x )
+#else
+#define MI_TRACEFN( x )
+#endif // MI_USE_DEBUG_TRACE_FN
diff --git a/tools/lldb-mi/MIUtilFileStd.cpp b/tools/lldb-mi/MIUtilFileStd.cpp
new file mode 100644
index 000000000000..853fd7455680
--- /dev/null
+++ b/tools/lldb-mi/MIUtilFileStd.cpp
@@ -0,0 +1,290 @@
+//===-- MIUtilFileStd.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilFileStd.cpp
+//
+// Overview: CMIUtilFileStd implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third party headers
+#include <stdio.h>
+#include <assert.h>
+#include <string.h> // For strerror()
+#include <cerrno>
+
+// In-house headers:
+#include "MIUtilFileStd.h"
+#include "MICmnResources.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilFileStd constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilFileStd::CMIUtilFileStd( void )
+: m_fileNamePath( CMIUtilString() )
+, m_pFileHandle( nullptr )
+#if defined( _MSC_VER )
+, m_constCharNewLine( "\r\n" )
+#else
+, m_constCharNewLine( "\n" )
+#endif // #if defined( _MSC_VER )
+, m_bFileError( false )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilFileStd destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilFileStd::~CMIUtilFileStd( void )
+{
+ Close();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Open file for writing. On the first call to this function after *this object
+// is created the file is either created or replace, from then on open only opens
+// an existing file.
+// Type: Method.
+// Args: vFileNamePath - (R) File name path.
+// vwrbNewCreated - (W) True - file recreated, false - file appended too.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilFileStd::CreateWrite( const CMIUtilString & vFileNamePath, bool & vwrbNewCreated )
+{
+ // Reset
+ m_bFileError = false;
+ vwrbNewCreated = false;
+
+ if( vFileNamePath.empty() )
+ {
+ m_bFileError = true;
+ SetErrorDescription( MIRSRC( IDS_UTIL_FILE_ERR_INVALID_PATHNAME ) );
+ return MIstatus::failure;
+ }
+
+ // File is already open so exit
+ if( m_pFileHandle != nullptr )
+ return MIstatus::success;
+
+#if !defined( _MSC_VER )
+ // Open with 'write' and 'binary' mode
+ m_pFileHandle = ::fopen( vFileNamePath.c_str(), "wb" );
+#else
+ // Open a file with exclusive write and shared read permissions
+ m_pFileHandle = ::_fsopen( vFileNamePath.c_str(), "wb", _SH_DENYWR );
+#endif // !defined( _MSC_VER )
+
+ if( m_pFileHandle == nullptr )
+ {
+ m_bFileError = true;
+ SetErrorDescriptionn( MIRSRC( IDS_UTIL_FILE_ERR_OPENING_FILE ), strerror( errno ), vFileNamePath.c_str() );
+ return MIstatus::failure;
+ }
+
+ vwrbNewCreated = true;
+ m_fileNamePath = vFileNamePath;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Write data to existing opened file.
+// Type: Method.
+// Args: vData - (R) Text data.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilFileStd::Write( const CMIUtilString & vData )
+{
+ if( vData.size() == 0 )
+ return MIstatus::success;
+
+ if( m_bFileError )
+ return MIstatus::failure;
+
+ if( m_pFileHandle == nullptr )
+ {
+ m_bFileError = true;
+ SetErrorDescriptionn( MIRSRC( IDE_UTIL_FILE_ERR_WRITING_NOTOPEN ), m_fileNamePath.c_str() );
+ return MIstatus::failure;
+ }
+
+ // Get the string size
+ MIuint size = vData.size();
+ if( ::fwrite( vData.c_str(), 1, size, m_pFileHandle ) == size )
+ {
+ // Flush the data to the file
+ ::fflush( m_pFileHandle );
+ return MIstatus::success;
+ }
+
+ // Not all of the data has been transferred
+ m_bFileError = true;
+ SetErrorDescriptionn( MIRSRC( IDE_UTIL_FILE_ERR_WRITING_FILE ), m_fileNamePath.c_str() );
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Write data to existing opened file.
+// Type: Method.
+// Args: vData - (R) Text data.
+// vCharCnt - (R) Text data length.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilFileStd::Write( const MIchar * vpData, const MIuint vCharCnt )
+{
+ if( vCharCnt == 0 )
+ return MIstatus::success;
+
+ if( m_bFileError )
+ return MIstatus::failure;
+
+ if( m_pFileHandle == nullptr )
+ {
+ m_bFileError = true;
+ SetErrorDescriptionn( MIRSRC( IDE_UTIL_FILE_ERR_WRITING_NOTOPEN ), m_fileNamePath.c_str() );
+ return MIstatus::failure;
+ }
+
+ if( ::fwrite( vpData, 1, vCharCnt, m_pFileHandle ) == vCharCnt )
+ {
+ // Flush the data to the file
+ ::fflush( m_pFileHandle );
+ return MIstatus::success;
+ }
+
+ // Not all of the data has been transferred
+ m_bFileError = true;
+ SetErrorDescriptionn( MIRSRC( IDE_UTIL_FILE_ERR_WRITING_FILE ), m_fileNamePath.c_str() );
+ return MIstatus::failure;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Close existing opened file. Note Close() must must an open!
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMIUtilFileStd::Close( void )
+{
+ if( m_pFileHandle == nullptr )
+ return;
+
+ ::fclose( m_pFileHandle );
+ m_pFileHandle = nullptr;
+ //m_bFileError = false; Do not reset as want to remain until next attempt at open or create
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve state of whether the file is ok.
+// Type: Method.
+// Args: None.
+// Return: True - file ok.
+// False - file has a problem.
+// Throws: None.
+//--
+bool CMIUtilFileStd::IsOk( void ) const
+{
+ return !m_bFileError;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Status on a file existing already.
+// Type: Method.
+// Args: vFileNamePath.
+// Return: True - Exists.
+// False - Not found.
+// Throws: None.
+//--
+bool CMIUtilFileStd::IsFileExist( const CMIUtilString & vFileNamePath ) const
+{
+ if( vFileNamePath.empty() )
+ return false;
+
+ FILE * pTmp = nullptr;
+ pTmp = ::fopen( vFileNamePath.c_str(), "wb" );
+ if( pTmp != nullptr )
+ {
+ ::fclose( pTmp );
+ return true;
+ }
+
+ return false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the file current carriage line return characters used.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString & - Text.
+// Throws: None.
+//--
+const CMIUtilString & CMIUtilFileStd::GetLineReturn( void ) const
+{
+ return m_constCharNewLine;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Given a file name directory path, strip off the filename and return the path.
+// It look for either backslash or forward slash.
+// Type: Method.
+// Args: vDirectoryPath - (R) Text directory path.
+// Return: CMIUtilString - Directory path.
+// Throws: None.
+//--
+CMIUtilString CMIUtilFileStd::StripOffFileName( const CMIUtilString & vDirectoryPath ) const
+{
+ const MIint nPos = vDirectoryPath.rfind( '\\' );
+ MIint nPos2 = vDirectoryPath.rfind( '/' );
+ if( (nPos == (MIint) std::string::npos) && (nPos2 == (MIint) std::string::npos) )
+ return vDirectoryPath;
+
+ if( nPos > nPos2 )
+ nPos2 = nPos;
+
+ const CMIUtilString strPath( vDirectoryPath.substr( 0, nPos2 ).c_str() );
+ return strPath;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Return either backslash or forward slash appropriate to the OS this applilcation
+// is running on.
+// Type: Static method.
+// Args: None.
+// Return: MIchar - '/' or '\' character.
+// Throws: None.
+//--
+MIchar CMIUtilFileStd::GetSlash( void )
+{
+#if !defined( _MSC_VER )
+ return '/';
+#else
+ return '\\';
+#endif // !defined( _MSC_VER )
+}
diff --git a/tools/lldb-mi/MIUtilFileStd.h b/tools/lldb-mi/MIUtilFileStd.h
new file mode 100644
index 000000000000..b6655b2ecfe9
--- /dev/null
+++ b/tools/lldb-mi/MIUtilFileStd.h
@@ -0,0 +1,65 @@
+//===-- MIUtilFileStd.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilFileStd.h
+//
+// Overview: CMIUtilFileStd interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MIUtilString.h"
+#include "MICmnBase.h"
+
+//++ ============================================================================
+// Details: MI common code utility class. File handling.
+// Gotchas: None.
+// Authors: Aidan Dodds 10/03/2014.
+// Changes: None.
+//--
+class CMIUtilFileStd : public CMICmnBase
+{
+// Static:
+public:
+ static MIchar GetSlash( void );
+
+// Methods:
+public:
+ /* ctor */ CMIUtilFileStd( void );
+ //
+ bool CreateWrite( const CMIUtilString & vFileNamePath, bool & vwrbNewCreated );
+ bool Write( const CMIUtilString & vData );
+ bool Write( const MIchar * vpData, const MIuint vCharCnt );
+ void Close( void );
+ bool IsOk( void ) const;
+ bool IsFileExist( const CMIUtilString & vFileNamePath ) const;
+ const CMIUtilString & GetLineReturn( void ) const;
+ CMIUtilString StripOffFileName( const CMIUtilString & vDirectoryPath ) const;
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMIUtilFileStd( void );
+
+// Attributes:
+private:
+ CMIUtilString m_fileNamePath;
+ FILE * m_pFileHandle;
+ CMIUtilString m_constCharNewLine;
+ bool m_bFileError; // True = have a file error ATM, false = all ok
+};
+
diff --git a/tools/lldb-mi/MIUtilMapIdToVariant.cpp b/tools/lldb-mi/MIUtilMapIdToVariant.cpp
new file mode 100644
index 000000000000..485ae2c0f0d2
--- /dev/null
+++ b/tools/lldb-mi/MIUtilMapIdToVariant.cpp
@@ -0,0 +1,124 @@
+//===-- MIUtilMapIdToVariant.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilMapIdToVariant.cpp
+//
+// Overview: CMIUtilMapIdToVariant implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MIUtilMapIdToVariant.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilMapIdToVariant constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilMapIdToVariant::CMIUtilMapIdToVariant( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilMapIdToVariant destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilMapIdToVariant::~CMIUtilMapIdToVariant( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Remove at the data from *this container.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMIUtilMapIdToVariant::Clear( void )
+{
+ m_mapKeyToVariantValue.clear();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Check an ID is present already in *this container.
+// Type: Method.
+// Args: vId - (R) Unique ID i.e. GUID.
+// Return: True - registered.
+// False - not found.
+// Throws: None.
+//--
+bool CMIUtilMapIdToVariant::HaveAlready( const CMIUtilString & vId ) const
+{
+ const MapKeyToVariantValue_t::const_iterator it = m_mapKeyToVariantValue.find( vId );
+ if( it != m_mapKeyToVariantValue.end() )
+ return true;
+
+ return false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine if *this container is currently holding any data.
+// Type: Method.
+// Args: None.
+// Return: bool - True - Yes empty, false - one or more data object present.
+// Throws: None.
+//--
+bool CMIUtilMapIdToVariant::IsEmpty( void ) const
+{
+ return m_mapKeyToVariantValue.empty();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Check the ID is valid to be registered.
+// Type: Method.
+// Args: vId - (R) Unique ID i.e. GUID.
+// Return: True - valid.
+// False - not valid.
+// Throws: None.
+//--
+bool CMIUtilMapIdToVariant::IsValid( const CMIUtilString & vId ) const
+{
+ bool bValid = true;
+
+ if( vId.empty() )
+ bValid = false;
+
+ return bValid;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Remove from *this contain a data object specified by ID. The data object
+// when removed also calls its destructor should it have one.
+// Type: Method.
+// Args: vId - (R) Unique ID i.e. GUID.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilMapIdToVariant::Remove( const CMIUtilString & vId )
+{
+ const MapKeyToVariantValue_t::const_iterator it = m_mapKeyToVariantValue.find( vId );
+ if( it != m_mapKeyToVariantValue.end() )
+ {
+ m_mapKeyToVariantValue.erase( it );
+ }
+
+ return MIstatus::success;
+}
diff --git a/tools/lldb-mi/MIUtilMapIdToVariant.h b/tools/lldb-mi/MIUtilMapIdToVariant.h
new file mode 100644
index 000000000000..9570bfa0306f
--- /dev/null
+++ b/tools/lldb-mi/MIUtilMapIdToVariant.h
@@ -0,0 +1,148 @@
+//===-- MIUtilMapIdToVariant.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilMapIdToVariant.h
+//
+// Overview: CMIUtilMapIdToVariant interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <map>
+
+// In-house headers:
+#include "MICmnBase.h"
+#include "MICmnResources.h"
+#include "MIUtilString.h"
+#include "MIUtilVariant.h"
+
+//++ ============================================================================
+// Details: MI common code utility class. Map type container that hold general
+// object types (by being wrappin an variant wrapper)
+// objects by ID.
+// Gotchas: None.
+// Authors: Illya Rudkin 19/06/2014.
+// Changes: None.
+//--
+class CMIUtilMapIdToVariant : public CMICmnBase
+{
+// Methods:
+public:
+ /* ctor */ CMIUtilMapIdToVariant( void );
+
+ template< typename T >
+ bool Add( const CMIUtilString & vId, const T & vData );
+ void Clear( void );
+ template< typename T >
+ bool Get( const CMIUtilString & vId, T & vrwData, bool & vrwbFound ) const;
+ bool HaveAlready( const CMIUtilString & vId ) const;
+ bool IsEmpty( void ) const;
+ bool Remove( const CMIUtilString & vId );
+
+// Overridden:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMIUtilMapIdToVariant( void );
+
+// Typdefs:
+private:
+ typedef std::map< CMIUtilString, CMIUtilVariant > MapKeyToVariantValue_t;
+ typedef std::pair< CMIUtilString, CMIUtilVariant > MapPairKeyToVariantValue_t;
+
+// Methods:
+private:
+ bool IsValid( const CMIUtilString & vId ) const;
+
+// Attributes:
+ MapKeyToVariantValue_t m_mapKeyToVariantValue;
+};
+
+//++ ------------------------------------------------------------------------------------
+// Details: Add to *this container a data object of general type identified by an ID.
+// If the data with that ID already exists in the container it is replace with
+// the new data specified.
+// Type: Method.
+// Args: T - The data object's variable type.
+// vId - (R) Unique ID i.e. GUID.
+// vData - (R) The general data object to be stored of some type.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+template< typename T >
+bool CMIUtilMapIdToVariant::Add( const CMIUtilString & vId, const T & vData )
+{
+ if( !IsValid( vId ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_VARIANT_ERR_MAP_KEY_INVALID ), vId.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ const bool bOk = HaveAlready( vId ) ? Remove( vId ) : MIstatus::success;
+ if( bOk )
+ {
+ CMIUtilVariant data;
+ data.Set< T >( vData );
+ MapPairKeyToVariantValue_t pr( vId, data );
+ m_mapKeyToVariantValue.insert( pr );
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve a data object from *this container identified by the specified ID.
+// Type: Method.
+// Args: T - The data object's variable type.
+// vId - (R) Unique ID i.e. GUID.
+// vrwData - (W) Copy of the data object held.
+// vrwbFound - (W) True = data found, false = data not found.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+template< typename T >
+bool CMIUtilMapIdToVariant::Get( const CMIUtilString & vId, T & vrwData, bool & vrwbFound ) const
+{
+ vrwbFound = false;
+
+ if( !IsValid( vId ) )
+ {
+ SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_VARIANT_ERR_MAP_KEY_INVALID ), vId.c_str() ) );
+ return MIstatus::failure;
+ }
+
+ const MapKeyToVariantValue_t::const_iterator it = m_mapKeyToVariantValue.find( vId );
+ if( it != m_mapKeyToVariantValue.end() )
+ {
+ const CMIUtilVariant & rData = (*it).second;
+ const T * pDataObj = rData.Get< T >();
+ if( pDataObj != nullptr )
+ {
+ vrwbFound = true;
+ vrwData = *pDataObj;
+ return MIstatus::success;
+ }
+ else
+ {
+ SetErrorDescription( MIRSRC( IDS_VARIANT_ERR_USED_BASECLASS ) );
+ return MIstatus::failure;
+ }
+ }
+
+ return MIstatus::success;
+}
diff --git a/tools/lldb-mi/MIUtilSingletonBase.h b/tools/lldb-mi/MIUtilSingletonBase.h
new file mode 100644
index 000000000000..23e971014882
--- /dev/null
+++ b/tools/lldb-mi/MIUtilSingletonBase.h
@@ -0,0 +1,71 @@
+//===-- MIUtilSingletonBase.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilSingletonBase.h
+//
+// Overview: MI::ISingleton interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+namespace MI
+{
+
+// MI::ISingleton base class usage:
+//
+// class CMIDerivedClass
+// : public MI::ISingleton< CMIDerivedClass >
+// {
+// friend MI::ISingleton< CMIDerivedClass >;
+//
+// // Overridden:
+// public:
+// // From MI::ISingleton
+// virtual bool Initialize( void );
+// virtual bool Shutdown( void );
+// };
+
+//++ ============================================================================
+// Details: Base class for the singleton pattern.
+// Gotchas: Derived class must specify MI::ISingleton<> as a friend class.
+// Authors: Aidan Dodds 17/03/2014.
+// Changes: None.
+//--
+template< typename T >
+class ISingleton
+{
+// Statics:
+public:
+ // Return an instance of the derived class
+ static T & Instance( void )
+ {
+ // This will fail if the derived class has not
+ // declared itself to be a friend of MI::ISingleton
+ static T instance;
+
+ return instance;
+ }
+
+// Overrideable:
+public:
+ virtual bool Initialize( void ) = 0;
+ virtual bool Shutdown( void ) = 0;
+ //
+ /* dtor */ virtual ~ISingleton( void ) { };
+};
+
+} // namespace MI
+
diff --git a/tools/lldb-mi/MIUtilSingletonHelper.h b/tools/lldb-mi/MIUtilSingletonHelper.h
new file mode 100644
index 000000000000..ad36366830b7
--- /dev/null
+++ b/tools/lldb-mi/MIUtilSingletonHelper.h
@@ -0,0 +1,95 @@
+//===-- MIUtilSingletonHelper.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilSingletonHelper.h
+//
+// Overview: Contains template functions to aid the initialisation and
+// shutdown of MI modules. MI modules (or components) can
+// use other MI modules to help them achieve their one task
+// (Modules only do one task).
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+namespace MI
+{
+
+// In house headers:
+#include "MIUtilString.h"
+#include "MICmnResources.h"
+
+//++ ============================================================================
+// Details: Short cut helper function to simplify repeated initialisation of
+// MI components (singletons) required by a client module.
+// Type: Template method.
+// Args: vErrorResrcId - (R) The string resource ID error message identifier to place in errMsg.
+// vwrbOk - (RW) On input True = Try to initalise MI driver module.
+// On output True = MI driver module initialise successfully.
+// vwrErrMsg - (W) MI driver module initialise error description on failure.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Authors: Aidan Dodds 17/03/2014.
+// Changes: None.
+//--
+template< typename T >
+bool ModuleInit( const MIint vErrorResrcId, bool & vwrbOk, CMIUtilString & vwrErrMsg )
+{
+ if( vwrbOk && !T::Instance().Initialize() )
+ {
+ vwrbOk = MIstatus::failure;
+ vwrErrMsg = CMIUtilString::Format( MIRSRC( vErrorResrcId ), T::Instance().GetErrorDescription().c_str() );
+ }
+
+ return vwrbOk;
+}
+
+//++ ============================================================================
+// Details: Short cut helper function to simplify repeated shutodown of
+// MI components (singletons) required by a client module.
+// Type: Template method.
+// Args: vErrorResrcId - (R) The string resource ID error message identifier
+// to place in errMsg.
+// vwrbOk - (W) If not already false make false on module
+// shutdown failure.
+// vwrErrMsg - (RW) Append to existing error description string MI
+// driver module initialise error description on
+// failure.
+// Return: True - Module shutdown succeeded.
+// False - Module shutdown failed.
+// Authors: Aidan Dodds 17/03/2014.
+// Changes: None.
+//--
+template< typename T >
+bool ModuleShutdown( const MIint vErrorResrcId, bool & vwrbOk, CMIUtilString & vwrErrMsg )
+{
+ bool bOk = MIstatus::success;
+
+ if( !T::Instance().Shutdown() )
+ {
+ const bool bMoreThanOneError( !vwrErrMsg.empty() );
+ bOk = MIstatus::failure;
+ if( bMoreThanOneError )
+ vwrErrMsg += ", ";
+ vwrErrMsg += CMIUtilString::Format( MIRSRC( vErrorResrcId ), T::Instance().GetErrorDescription().c_str() );
+ }
+
+ vwrbOk = bOk ? vwrbOk : MIstatus::failure;
+
+ return bOk;
+}
+
+} // namespace MI
+
diff --git a/tools/lldb-mi/MIUtilString.cpp b/tools/lldb-mi/MIUtilString.cpp
new file mode 100644
index 000000000000..11c246290cab
--- /dev/null
+++ b/tools/lldb-mi/MIUtilString.cpp
@@ -0,0 +1,680 @@
+//===-- MIUtilString.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilString.h
+//
+// Overview: CMIUtilString implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third party headers
+#include <memory> // std::unique_ptr
+#include <stdarg.h> // va_list, va_start, var_end
+#include <sstream> // std::stringstream
+#include <string.h> // for strcpy
+#include <limits.h> // for ULONG_MAX
+
+// In-house headers:
+#include "MIUtilString.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilString constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilString::CMIUtilString( void )
+: std::string()
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilString constructor.
+// Type: Method.
+// Args: vpData - Pointer to UTF8 text data.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilString::CMIUtilString( const MIchar * vpData )
+: std::string( vpData )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilString constructor.
+// Type: Method.
+// Args: vpData - Pointer to UTF8 text data.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilString::CMIUtilString( const MIchar * const * vpData )
+: std::string( (const char *) vpData )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilString assigment operator.
+// Type: Method.
+// Args: vpRhs - Pointer to UTF8 text data.
+// Return: CMIUtilString & - *this string.
+// Throws: None.
+//--
+CMIUtilString & CMIUtilString::operator= ( const MIchar * vpRhs )
+{
+ if( *this == vpRhs )
+ return *this;
+
+ if( vpRhs != nullptr )
+ {
+ assign( vpRhs );
+ }
+
+ return *this;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilString assigment operator.
+// Type: Method.
+// Args: vrRhs - The other string to copy from.
+// Return: CMIUtilString & - *this string.
+// Throws: None.
+//--
+CMIUtilString & CMIUtilString::operator= ( const std::string & vrRhs )
+{
+ if( *this == vrRhs )
+ return *this;
+
+ assign( vrRhs );
+
+ return *this;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilString destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilString::~CMIUtilString( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Perform a snprintf format style on a string data. A new string object is
+// created and returned.
+// Type: Static method.
+// Args: vrFormat - (R) Format string data instruction.
+// vArgs - (R) Var list args of any type.
+// Return: CMIUtilString - Number of splits found in the string data.
+// Throws: None.
+//--
+CMIUtilString CMIUtilString::FormatPriv( const CMIUtilString & vrFormat, va_list vArgs )
+{
+ CMIUtilString strResult;
+ MIint nFinal = 0;
+ MIint n = vrFormat.size();
+
+ // IOR: mysterious crash in this function on some windows builds not able to duplicate
+ // but found article which may be related. Crash occurs in vsnprintf() or va_copy()
+ // Duplicate vArgs va_list argument pointer to ensure that it can be safely used in
+ // a new frame
+ // http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html
+ va_list argsDup;
+ va_copy( argsDup, vArgs );
+
+ // Create a copy va_list to reset when we spin
+ va_list argsCpy;
+ va_copy( argsCpy, argsDup );
+
+ if( n == 0 )
+ return strResult;
+
+ n = n << 4; // Reserve 16 times as much the length of the vrFormat
+
+ std::unique_ptr< char[] > pFormatted;
+ while( 1 )
+ {
+ pFormatted.reset( new char[ n + 1 ] ); // +1 for safety margin
+ ::strncpy( &pFormatted[ 0 ], vrFormat.c_str(), n );
+
+ // We need to restore the variable argument list pointer to the start again
+ // before running vsnprintf() more then once
+ va_copy( argsDup, argsCpy );
+
+ nFinal = ::vsnprintf( &pFormatted[ 0 ], n, vrFormat.c_str(), argsDup );
+ if( (nFinal < 0) || (nFinal >= n) )
+ n += abs( nFinal - n + 1 );
+ else
+ break;
+ }
+
+ va_end( argsCpy );
+ va_end( argsDup );
+
+ strResult = pFormatted.get();
+
+ return strResult;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Perform a snprintf format style on a string data. A new string object is
+// created and returned.
+// Type: Static method.
+// Args: vrFormat - (R) Format string data instruction.
+// ... - (R) Var list args of any type.
+// Return: CMIUtilString - Number of splits found in the string data.
+// Throws: None.
+//--
+CMIUtilString CMIUtilString::Format( const CMIUtilString & vrFormating, ... )
+{
+ va_list args;
+ va_start( args, vrFormating );
+ CMIUtilString strResult = CMIUtilString::FormatPriv( vrFormating, args );
+ va_end( args );
+
+ return strResult;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Perform a snprintf format style on a string data. A new string object is
+// created and returned.
+// Type: Static method.
+// Args: vrFormat - (R) Format string data instruction.
+// vArgs - (R) Var list args of any type.
+// Return: CMIUtilString - Number of splits found in the string data.
+// Throws: None.
+//--
+CMIUtilString CMIUtilString::FormatValist( const CMIUtilString & vrFormating, va_list vArgs )
+{
+ return CMIUtilString::FormatPriv( vrFormating, vArgs );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Splits string into array of strings using delimiter. If multiple delimiter
+// are found in sequence then they are not added to the list of splits.
+// Type: Method.
+// Args: vData - (R) String data to be split up.
+// vDelimiter - (R) Delimiter char or text.
+// vwVecSplits - (W) Container of splits found in string data.
+// Return: MIuint - Number of splits found in the string data.
+// Throws: None.
+//--
+MIuint CMIUtilString::Split( const CMIUtilString & vDelimiter, VecString_t & vwVecSplits ) const
+{
+ vwVecSplits.clear();
+
+ if( this->empty() || vDelimiter.empty() )
+ return 0;
+
+ MIint nPos = find( vDelimiter );
+ if( nPos == (MIint) std::string::npos )
+ {
+ vwVecSplits.push_back( *this );
+ return 1;
+ }
+ const MIint strLen( length() );
+ if( nPos == strLen )
+ {
+ vwVecSplits.push_back( *this );
+ return 1;
+ }
+
+ MIuint nAdd1( 1 );
+ if( (nPos > 0) && (substr( 0, nPos ) != vDelimiter) )
+ {
+ nPos = 0;
+ nAdd1 = 0;
+ }
+ MIint nPos2 = find( vDelimiter, nPos + 1 );
+ while( nPos2 != (MIint) std::string::npos )
+ {
+ const MIuint len( nPos2 - nPos - nAdd1 );
+ const std::string strSection( substr( nPos + nAdd1, len ) );
+ if( strSection != vDelimiter )
+ vwVecSplits.push_back( strSection.c_str() );
+ nPos += len + 1;
+ nPos2 = find( vDelimiter, nPos + 1 );
+ nAdd1 = 0;
+ }
+ const std::string strSection( substr( nPos, strLen - nPos ) );
+ if( (strSection.length() != 0) && (strSection != vDelimiter) )
+ vwVecSplits.push_back( strSection.c_str() );
+
+ return vwVecSplits.size();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Splits string into array of strings using delimiter. However the string is
+// also considered for text surrounded by quotes. Text with quotes including the
+// delimiter is treated as a whole. If multiple delimiter are found in sequence
+// then they are not added to the list of splits. Quotes that are embedded in the
+// the string as string formatted quotes are ignored (proceeded by a '\\') i.e.
+// "\"MI GDB local C++.cpp\":88".
+// Type: Method.
+// Args: vData - (R) String data to be split up.
+// vDelimiter - (R) Delimiter char or text.
+// vwVecSplits - (W) Container of splits found in string data.
+// Return: MIuint - Number of splits found in the string data.
+// Throws: None.
+//--
+MIuint CMIUtilString::SplitConsiderQuotes( const CMIUtilString & vDelimiter, VecString_t & vwVecSplits ) const
+{
+ vwVecSplits.clear();
+
+ if( this->empty() || vDelimiter.empty() )
+ return 0;
+
+ MIint nPos = find( vDelimiter );
+ if( nPos == (MIint) std::string::npos )
+ {
+ vwVecSplits.push_back( *this );
+ return 1;
+ }
+ const MIint strLen( length() );
+ if( nPos == strLen )
+ {
+ vwVecSplits.push_back( *this );
+ return 1;
+ }
+
+ // Look for more quotes
+ bool bHaveQuotes = false;
+ const MIchar cBckSlash = '\\';
+ const MIchar cQuote = '"';
+ MIint nPosQ = find( cQuote );
+ MIint nPosQ2 = (MIint) std::string::npos;
+ if( nPosQ != (MIint) std::string::npos )
+ {
+ nPosQ2 = nPosQ + 1;
+ while( nPosQ2 < strLen )
+ {
+ nPosQ2 = find( cQuote, nPosQ2 );
+ if( (nPosQ2 == (MIint) std::string::npos) || (at( nPosQ2 - 1 ) != cBckSlash) )
+ break;
+ nPosQ2++;
+ }
+ bHaveQuotes = (nPosQ2 != (MIint) std::string::npos);
+ }
+
+ MIuint nAdd1( 1 );
+ if( (nPos > 0) && (substr( 0, nPos ) != vDelimiter) )
+ {
+ nPos = 0;
+ nAdd1 = 0;
+ }
+ MIint nPos2 = find( vDelimiter, nPos + 1 );
+ while( nPos2 != (MIint) std::string::npos )
+ {
+ if( !bHaveQuotes || (bHaveQuotes && ((nPos2 > nPosQ2) || (nPos2 < nPosQ))) )
+ {
+ // Extract text or quoted text
+ const MIuint len( nPos2 - nPos - nAdd1 );
+ const std::string strSection( substr( nPos + nAdd1, len ) );
+ if( strSection != vDelimiter )
+ vwVecSplits.push_back( strSection.c_str() );
+ nPos += len + 1;
+ nPos2 = find( vDelimiter, nPos + 1 );
+ nAdd1 = 0;
+
+ if( bHaveQuotes && (nPos2 > nPosQ2) )
+ {
+ // Reset, look for more quotes
+ bHaveQuotes = false;
+ nPosQ = find( cQuote, nPos );
+ nPosQ2 = (MIint) std::string::npos;
+ if( nPosQ != (MIint) std::string::npos )
+ {
+ nPosQ2 = find( cQuote, nPosQ + 1 );
+ bHaveQuotes = (nPosQ2 != (MIint) std::string::npos);
+ }
+ }
+ }
+ else
+ {
+ // Skip passed text in quotes
+ nPos2 = find( vDelimiter, nPosQ2 + 1 );
+ }
+ }
+ const std::string strSection( substr( nPos, strLen - nPos ) );
+ if( (strSection.length() != 0) && (strSection != vDelimiter) )
+ vwVecSplits.push_back( strSection.c_str() );
+
+ return vwVecSplits.size();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Remove '\n' from the end of string if found. It does not alter
+// *this string.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - New version of the string.
+// Throws: None.
+//--
+CMIUtilString CMIUtilString::StripCREndOfLine( void ) const
+{
+ const MIint nPos = rfind( '\n' );
+ if( nPos == (MIint) std::string::npos )
+ return *this;
+
+ const CMIUtilString strNew( substr( 0, nPos ).c_str() );
+
+ return strNew;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Remove all '\n' from the string and replace with a space. It does not alter
+// *this string.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - New version of the string.
+// Throws: None.
+//--
+CMIUtilString CMIUtilString::StripCRAll( void ) const
+{
+ return FindAndReplace( "\n", " " );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Find and replace all matches of a sub string with another string. It does not
+// alter *this string.
+// Type: Method.
+// Args: vFind - (R) The string to look for.
+// vReplaceWith - (R) The string to replace the vFind match.
+// Return: CMIUtilString - New version of the string.
+// Throws: None.
+//--
+CMIUtilString CMIUtilString::FindAndReplace( const CMIUtilString & vFind, const CMIUtilString & vReplaceWith ) const
+{
+ if( vFind.empty() || this->empty() )
+ return *this;
+
+ MIint nPos = find( vFind );
+ if( nPos == (MIint) std::string::npos )
+ return *this;
+
+ CMIUtilString strNew( *this );
+ while( nPos != (MIint) std::string::npos )
+ {
+ strNew.replace( nPos, vFind.length(), vReplaceWith );
+ nPos += vReplaceWith.length();
+ nPos = strNew.find( vFind, nPos );
+ }
+
+ return strNew;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Check if *this string is a decimal number.
+// Type: Method.
+// Args: None.
+// Return: bool - True = yes number, false not a number.
+// Throws: None.
+//--
+bool CMIUtilString::IsNumber( void ) const
+{
+ if( empty() )
+ return false;
+
+ if( (at( 0 ) == '-') && (length() == 1) )
+ return false;
+
+ const MIint nPos = find_first_not_of( "-.0123456789" );
+ if( nPos != (MIint) std::string::npos )
+ return false;
+
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Extract the number from the string. The number can be either a hexadecimal or
+// natural number. It cannot contain other non-numeric characters.
+// Type: Method.
+// Args: vwrNumber - (W) Number exracted from the string.
+// Return: bool - True = yes number, false not a number.
+// Throws: None.
+//--
+bool CMIUtilString::ExtractNumber( MIint64 & vwrNumber ) const
+{
+ vwrNumber = 0;
+
+ if( !IsNumber() )
+ {
+ if( ExtractNumberFromHexadecimal( vwrNumber ) )
+ return true;
+
+ return false;
+ }
+
+ std::stringstream ss( const_cast< CMIUtilString & >( *this ) );
+ ss >> vwrNumber;
+
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Extract the number from the hexadecimal string..
+// Type: Method.
+// Args: vwrNumber - (W) Number exracted from the string.
+// Return: bool - True = yes number, false not a number.
+// Throws: None.
+//--
+bool CMIUtilString::ExtractNumberFromHexadecimal( MIint64 & vwrNumber ) const
+{
+ vwrNumber = 0;
+
+ const MIint nPos = find_first_not_of( "x01234567890ABCDEFabcedf" );
+ if( nPos != (MIint) std::string::npos )
+ return false;
+
+ const MIint64 nNum = ::strtoul( this->c_str(), nullptr, 16 );
+ if( nNum != ULONG_MAX )
+ {
+ vwrNumber = nNum;
+ return true;
+ }
+
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine if the text is all valid alpha numeric characters. Letters can be
+// either upper or lower case.
+// Type: Static method.
+// Args: vrText - (R) The text data to examine.
+// Return: bool - True = yes all alpha, false = one or more chars is non alpha.
+// Throws: None.
+//--
+bool CMIUtilString::IsAllValidAlphaAndNumeric( const MIchar & vrText )
+{
+ const MIuint len = ::strlen( &vrText );
+ if( len == 0 )
+ return false;
+
+ MIchar * pPtr = const_cast< MIchar * >( &vrText );
+ for( MIuint i = 0; i < len; i++, pPtr++ )
+ {
+ const MIchar c = *pPtr;
+ if( ::isalnum( (int) c ) == 0 )
+ return false;
+ }
+
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Check if two strings share equal contents.
+// Type: Method.
+// Args: vrLhs - (R) String A.
+// vrRhs - (R) String B.
+// Return: bool - True = yes equal, false - different.
+// Throws: None.
+//--
+bool CMIUtilString::Compare( const CMIUtilString & vrLhs, const CMIUtilString & vrRhs )
+{
+ // Check the sizes match
+ if( vrLhs.size() != vrRhs.size() )
+ return false;
+
+ return (::strncmp( vrLhs.c_str(), vrRhs.c_str(), vrLhs.size() ) == 0);
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Remove from either end of *this string the following: " \t\n\v\f\r".
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Trimmed string.
+// Throws: None.
+//--
+CMIUtilString CMIUtilString::Trim( void ) const
+{
+ CMIUtilString strNew( *this );
+ const MIchar * pWhiteSpace = " \t\n\v\f\r";
+ const MIint nPos = find_last_not_of( pWhiteSpace );
+ if( nPos != (MIint) std::string::npos )
+ {
+ strNew = substr( 0, nPos + 1 ).c_str();
+ }
+ const MIint nPos2 = strNew.find_first_not_of( pWhiteSpace );
+ if( nPos2 != (MIint) std::string::npos )
+ {
+ strNew = strNew.substr( nPos2 ).c_str();
+ }
+
+ return strNew;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Remove from either end of *this string the specified character.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Trimmed string.
+// Throws: None.
+//--
+CMIUtilString CMIUtilString::Trim( const MIchar vChar ) const
+{
+ CMIUtilString strNew( *this );
+ const MIint nLen = strNew.length();
+ if( nLen > 1 )
+ {
+ if( (strNew[ 0 ] == vChar) && (strNew[ nLen - 1 ] == vChar) )
+ strNew = strNew.substr( 1, nLen - 2 ).c_str();
+ }
+
+ return strNew;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Do a printf equivalent for printing a number in binary i.e. "b%llB".
+// Type: Static method.
+// Args: vnDecimal - (R) The number to represent in binary.
+// Return: CMIUtilString - Binary number in text.
+// Throws: None.
+//--
+CMIUtilString CMIUtilString::FormatBinary( const MIuint64 vnDecimal )
+{
+ CMIUtilString strBinaryNumber;
+
+ const MIuint nConstBits = 64;
+ MIuint nRem[ nConstBits + 1 ];
+ MIint i = 0;
+ MIuint nLen = 0;
+ MIuint64 nNum = vnDecimal;
+ while( (nNum > 0) && (nLen < nConstBits) )
+ {
+ nRem[ i++ ] = nNum % 2;
+ nNum = nNum >> 1;
+ nLen++;
+ }
+ MIchar pN[ nConstBits + 1 ];
+ MIuint j = 0;
+ for( i = nLen; i > 0; --i, j++ )
+ {
+ pN[ j ] = '0' + nRem[ i - 1 ];
+ }
+ pN[ j ] = 0; // String NUL termination
+
+ strBinaryNumber = CMIUtilString::Format( "0b%s", &pN[ 0 ] );
+
+ return strBinaryNumber;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Remove from a string doubled up characters so only one set left. Characters
+// are only removed if the previous character is already a same character.
+// Type: Method.
+// Args: vChar - (R) The character to search for and remove adjacent duplicates.
+// Return: CMIUtilString - New version of the string.
+// Throws: None.
+//--
+CMIUtilString CMIUtilString::RemoveRepeatedCharacters( const MIchar vChar )
+{
+ return RemoveRepeatedCharacters( 0, vChar );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Recursively remove from a string doubled up characters so only one set left.
+// Characters are only removed if the previous character is already a same
+// character.
+// Type: Method.
+// Args: vChar - (R) The character to search for and remove adjacent duplicates.
+// vnPos - (R) Character position in the string.
+// Return: CMIUtilString - New version of the string.
+// Throws: None.
+//--
+CMIUtilString CMIUtilString::RemoveRepeatedCharacters( const MIint vnPos, const MIchar vChar )
+{
+ const MIchar cQuote = '"';
+
+ // Look for first quote of two
+ MIint nPos = find( cQuote, vnPos );
+ if( nPos == (MIint) std::string::npos )
+ return *this;
+
+ const MIint nPosNext = nPos + 1;
+ if( nPosNext > (MIint) length() )
+ return *this;
+
+ if( at( nPosNext ) == cQuote )
+ {
+ *this = substr( 0, nPos ) + substr( nPosNext, length() );
+ RemoveRepeatedCharacters( nPosNext, vChar );
+ }
+
+ return *this;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Is the text in *this string surrounded by quotes.
+// Type: Method.
+// Args: None.
+// Return: bool - True = Yes string is quoted, false = no quoted.
+// Throws: None.
+//--
+bool CMIUtilString::IsQuoted( void ) const
+{
+ const MIchar cQuote = '"';
+
+ if( at( 0 ) != cQuote )
+ return false;
+
+ const MIint nLen = length();
+ if( (nLen > 0) && (at( nLen - 1 ) != cQuote) )
+ return false;
+
+ return true;
+}
+ \ No newline at end of file
diff --git a/tools/lldb-mi/MIUtilString.h b/tools/lldb-mi/MIUtilString.h
new file mode 100644
index 000000000000..30b027a9d314
--- /dev/null
+++ b/tools/lldb-mi/MIUtilString.h
@@ -0,0 +1,85 @@
+//===-- MIUtilString.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilString.h
+//
+// Overview: CMIUtilString interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#include <string>
+#include <vector>
+
+// In-house headers:
+#include "MIDataTypes.h"
+
+//++ ============================================================================
+// Details: MI common code utility class. Used to help handle text.
+// Derived from std::string
+// Gotchas: None.
+// Authors: Illya Rudkin 02/02/2014.
+// Changes: None.
+//--
+class CMIUtilString : public std::string
+{
+// Typdefs:
+public:
+ typedef std::vector< CMIUtilString > VecString_t;
+
+// Static method:
+public:
+ static CMIUtilString Format( const CMIUtilString & vrFormating, ... );
+ static CMIUtilString FormatBinary( const MIuint64 vnDecimal );
+ static CMIUtilString FormatValist( const CMIUtilString & vrFormating, va_list vArgs );
+ static bool IsAllValidAlphaAndNumeric( const MIchar & vrText );
+ static bool Compare( const CMIUtilString & vrLhs, const CMIUtilString & vrRhs );
+
+// Methods:
+public:
+ /* ctor */ CMIUtilString( void );
+ /* ctor */ CMIUtilString( const MIchar * vpData );
+ /* ctor */ CMIUtilString( const MIchar * const * vpData );
+ //
+ bool ExtractNumber( MIint64 & vwrNumber ) const;
+ CMIUtilString FindAndReplace( const CMIUtilString & vFind, const CMIUtilString & vReplaceWith ) const;
+ bool IsNumber( void ) const;
+ bool IsQuoted( void ) const;
+ CMIUtilString RemoveRepeatedCharacters( const MIchar vChar );
+ MIuint Split( const CMIUtilString & vDelimiter, VecString_t & vwVecSplits ) const;
+ MIuint SplitConsiderQuotes( const CMIUtilString & vDelimiter, VecString_t & vwVecSplits ) const;
+ CMIUtilString StripCREndOfLine( void ) const;
+ CMIUtilString StripCRAll( void ) const;
+ CMIUtilString Trim( void ) const;
+ CMIUtilString Trim( const MIchar vChar ) const;
+ //
+ CMIUtilString & operator= ( const MIchar * vpRhs );
+ CMIUtilString & operator= ( const std::string & vrRhs );
+
+// Overrideable:
+public:
+ /* dtor */ virtual ~CMIUtilString( void );
+
+// Static method:
+private:
+ static CMIUtilString FormatPriv( const CMIUtilString & vrFormat, va_list vArgs );
+
+// Methods:
+private:
+ bool ExtractNumberFromHexadecimal( MIint64 & vwrNumber ) const;
+ CMIUtilString RemoveRepeatedCharacters( const MIint vnPos, const MIchar vChar );
+};
diff --git a/tools/lldb-mi/MIUtilSystemLinux.cpp b/tools/lldb-mi/MIUtilSystemLinux.cpp
new file mode 100644
index 000000000000..b1755a32a67e
--- /dev/null
+++ b/tools/lldb-mi/MIUtilSystemLinux.cpp
@@ -0,0 +1,119 @@
+//===-- MIUtilSystemLinux.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilSystemLinux.cpp
+//
+// Overview: CMIUtilSystemLinux implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#if defined( __FreeBSD__ ) || defined( __linux__ )
+
+// In-house headers:
+#include "MIUtilSystemLinux.h"
+#include "MICmnResources.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilSystemLinux constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilSystemLinux::CMIUtilSystemLinux( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilSystemLinux destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilSystemLinux::~CMIUtilSystemLinux( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the OS system error message for the given system error code.
+// Type: Method.
+// Args: vError - (R) OS error code value.
+// vrwErrorMsg - (W) The error message.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilSystemLinux::GetOSErrorMsg( const MIint vError, CMIUtilString & vrwErrorMsg ) const
+{
+ // Reset
+ vrwErrorMsg.clear();
+
+ bool bOk = MIstatus::failure;
+
+ // ToDo: Implement LINUX version
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve if possible the OS last error description.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Error description.
+// Throws: None.
+//--
+CMIUtilString CMIUtilSystemLinux::GetOSLastError( void ) const
+{
+ CMIUtilString errorMsg( "Error fn not implemented " );
+
+ // ToDo: Implement LINUX version
+
+ return errorMsg;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieves the fully qualified path for the this application. If the function
+// fails the string is filled with the error message.
+// Type: Method.
+// Args: vrwFileNamePath - (W) The excutable's name and path or last error description.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilSystemLinux::GetExecutablesPath( CMIUtilString & vrwFileNamePath ) const
+{
+ vrwFileNamePath = CMIUtilString( "." );
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieves the fully qualified path for the Log file for this application.
+// If the function fails the string is filled with the error message.
+// Append a dummy file name on the end of the path. This will be stripped off
+// later and the real log file name replaces it.
+// Type: Method.
+// Args: vrwFileNamePath - (W) The Log file's name and path or last error description.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilSystemLinux::GetLogFilesPath( CMIUtilString & vrwFileNamePath ) const
+{
+ vrwFileNamePath = CMIUtilString( "." );
+ return MIstatus::success;
+}
+
+#endif // #if defined( __linux__ )
diff --git a/tools/lldb-mi/MIUtilSystemLinux.h b/tools/lldb-mi/MIUtilSystemLinux.h
new file mode 100644
index 000000000000..1fd2c525992a
--- /dev/null
+++ b/tools/lldb-mi/MIUtilSystemLinux.h
@@ -0,0 +1,57 @@
+//===-- CMIUtilSystemLinux.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: CMIUtilSystemLinux.h
+//
+// Overview: CMIUtilSystemLinux interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+#if defined( __FreeBSD__ ) || defined( __linux__ )
+
+// In-house headers:
+#include "MIUtilString.h"
+
+//++ ============================================================================
+// Details: MI common code utility class. Used to set or retrieve information
+// about the current system or user.
+// *** If you change, remove or add functionality it must be replicated
+// *** for the all platforms supported; Windows, OSX, LINUX
+// Gotchas: None.
+// Authors: Illya Rudkin 29/01/2014.
+// Changes: None.
+//--
+class CMIUtilSystemLinux
+{
+// Methods:
+public:
+ /* ctor */ CMIUtilSystemLinux( void );
+
+ bool GetOSErrorMsg( const MIint vError, CMIUtilString & vrwErrorMsg ) const;
+ CMIUtilString GetOSLastError( void ) const;
+ bool GetExecutablesPath( CMIUtilString & vrwFileNamePath ) const;
+ bool GetLogFilesPath( CMIUtilString & vrwFileNamePath ) const;
+
+// Overrideable:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMIUtilSystemLinux( void );
+};
+
+typedef CMIUtilSystemLinux CMIUtilSystem;
+
+#endif // #if defined( __linux__ )
diff --git a/tools/lldb-mi/MIUtilSystemOsx.cpp b/tools/lldb-mi/MIUtilSystemOsx.cpp
new file mode 100644
index 000000000000..e291304789d5
--- /dev/null
+++ b/tools/lldb-mi/MIUtilSystemOsx.cpp
@@ -0,0 +1,125 @@
+//===-- MIUtilSystemOsx.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilSystemOsx.cpp
+//
+// Overview: CMIUtilSystemOsx implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#if defined( __APPLE__ )
+
+// In-house headers:
+#include "MIUtilSystemOsx.h"
+#include "MICmnResources.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilSystemOsx constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilSystemOsx::CMIUtilSystemOsx( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilSystemOsx destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilSystemOsx::~CMIUtilSystemOsx( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the OS system error message for the given system error code.
+// Type: Method.
+// Args: vError - (R) OS error code value.
+// vrwErrorMsg - (W) The error message.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilSystemOsx::GetOSErrorMsg( const MIint vError, CMIUtilString & vrwErrorMsg ) const
+{
+ // Reset
+ vrwErrorMsg.clear();
+
+ bool bOk = MIstatus::failure;
+
+ // ToDo: Implement LINUX version
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve if possible the OS last error description.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Error description.
+// Throws: None.
+//--
+CMIUtilString CMIUtilSystemOsx::GetOSLastError( void ) const
+{
+ CMIUtilString errorMsg( "Error fn not implemented" );
+
+ // ToDo: Implement LINUX version
+
+ return errorMsg;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieves the fully qualified path for the this application. If the function
+// fails the string is filled with the error message.
+// Type: Method.
+// Args: vrwFileNamePath - (W) The excutable's name and path or last error description.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilSystemOsx::GetExecutablesPath( CMIUtilString & vrwFileNamePath ) const
+{
+ bool bOk = MIstatus::failure;
+
+ // ToDo: Implement OSX version
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieves the fully qualified path for the Log file for this application.
+// If the function fails the string is filled with the error message.
+// Append a dummy file name on the end of the path. This will be stripped off
+// later and the real log file name replaces it.
+// Type: Method.
+// Args: vrwFileNamePath - (W) The Log file's name and path or last error description.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilSystemOsx::GetLogFilesPath( CMIUtilString & vrwFileNamePath ) const
+{
+ bool bOk = MIstatus::failure;
+
+ // ToDo: Implement OSX version
+
+ return bOk;
+}
+
+#endif // #if defined( __APPLE__ )
diff --git a/tools/lldb-mi/MIUtilSystemOsx.h b/tools/lldb-mi/MIUtilSystemOsx.h
new file mode 100644
index 000000000000..d0825c6e3441
--- /dev/null
+++ b/tools/lldb-mi/MIUtilSystemOsx.h
@@ -0,0 +1,57 @@
+//===-- MICmnConfig.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: CMIUtilSystemOsx.h
+//
+// Overview: CMIUtilSystemOsx interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+#if defined( __APPLE__ )
+
+// In-house headers:
+#include "MIUtilString.h"
+
+//++ ============================================================================
+// Details: MI common code utility class. Used to set or retrieve information
+// about the current system or user.
+// *** If you change, remove or add functionality it must be replicated
+// *** for the all platforms supported; Windows, OSX, LINUX
+// Gotchas: None.
+// Authors: Illya Rudkin 29/01/2014.
+// Changes: None.
+//--
+class CMIUtilSystemOsx
+{
+// Methods:
+public:
+ /* ctor */ CMIUtilSystemOsx( void );
+
+ bool GetOSErrorMsg( const MIint vError, CMIUtilString & vrwErrorMsg ) const;
+ CMIUtilString GetOSLastError( void ) const;
+ bool GetExecutablesPath( CMIUtilString & vrwFileNamePath ) const;
+ bool GetLogFilesPath( CMIUtilString & vrwFileNamePath ) const;
+
+// Overrideable:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMIUtilSystemOsx( void );
+};
+
+typedef CMIUtilSystemOsx CMIUtilSystem;
+
+#endif // #if defined( __APPLE__ )
diff --git a/tools/lldb-mi/MIUtilSystemWindows.cpp b/tools/lldb-mi/MIUtilSystemWindows.cpp
new file mode 100644
index 000000000000..5873aad0ec62
--- /dev/null
+++ b/tools/lldb-mi/MIUtilSystemWindows.cpp
@@ -0,0 +1,151 @@
+//===-- MIUtilSystemWindows.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilSystemWindows.cpp
+//
+// Overview: CMIUtilSystemWindows implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#if defined( _MSC_VER )
+
+// Third party headers
+#include <memory> // std::unique_ptr
+#include <Windows.h>
+#include <WinBase.h> // ::FormatMessage()
+
+// In-house headers:
+#include "MIUtilSystemWindows.h"
+#include "MICmnResources.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilSystemWindows constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilSystemWindows::CMIUtilSystemWindows( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilSystemWindows destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilSystemWindows::~CMIUtilSystemWindows( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the OS system error message for the given system error code.
+// Type: Method.
+// Args: vError - (R) OS error code value.
+// vrwErrorMsg - (W) The error message.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilSystemWindows::GetOSErrorMsg( const MIint vError, CMIUtilString & vrwErrorMsg ) const
+{
+ // Reset
+ vrwErrorMsg.clear();
+
+ const MIuint nBufLen = 1024;
+ std::unique_ptr< char[] > pBuffer;
+ pBuffer.reset( new char[ nBufLen ] );
+
+ // CMIUtilString Format is not used as cannot replicate the behavior of ::FormatMessage which
+ // can take into account locality while retrieving the error message from the system.
+ const int nLength = ::FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ nullptr, (DWORD) vError, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
+ reinterpret_cast< LPTSTR >( &pBuffer[ 0 ] ),
+ nBufLen, nullptr );
+ bool bOk = MIstatus::success;
+ if( nLength != 0 )
+ vrwErrorMsg = &pBuffer[ 0 ];
+ else
+ bOk = MIstatus::failure;
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve if possible the OS last error description.
+// Type: Method.
+// Args: None.
+// Return: CMIUtilString - Error description.
+// Throws: None.
+//--
+CMIUtilString CMIUtilSystemWindows::GetOSLastError( void ) const
+{
+ CMIUtilString errorMsg;
+ const DWORD dwLastError = ::GetLastError();
+ if( dwLastError != 0 )
+ {
+ if( !GetOSErrorMsg( dwLastError, errorMsg ) )
+ errorMsg = MIRSRC( IDE_OS_ERR_RETRIEVING );
+ }
+ else
+ errorMsg = MIRSRC( IDE_OS_ERR_UNKNOWN );
+
+ return errorMsg;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieves the fully qualified path for the this application. If the function
+// fails the string is filled with the error message.
+// Type: Method.
+// Args: vrwFileNamePath - (W) The excutable's name and path or last error description.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilSystemWindows::GetExecutablesPath( CMIUtilString & vrwFileNamePath ) const
+{
+ bool bOk = MIstatus::success;
+ HMODULE hModule = ::GetModuleHandle( nullptr );
+ char pPath[ MAX_PATH ];
+ const DWORD nLen = ::GetModuleFileName( hModule, &pPath[ 0 ], MAX_PATH );
+ const CMIUtilString strLastErr( GetOSLastError() );
+ if( (nLen != 0) && (strLastErr == "Unknown OS error") )
+ vrwFileNamePath = &pPath[ 0 ];
+ else
+ {
+ bOk = MIstatus::failure;
+ vrwFileNamePath = strLastErr;
+ }
+
+ return bOk;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieves the fully qualified path for the Log file for this application.
+// If the function fails the string is filled with the error message.
+// Type: Method.
+// Args: vrwFileNamePath - (W) The Log file's name and path or last error description.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilSystemWindows::GetLogFilesPath( CMIUtilString & vrwFileNamePath ) const
+{
+ return GetExecutablesPath( vrwFileNamePath );
+}
+
+#endif // #if defined( _MSC_VER )
diff --git a/tools/lldb-mi/MIUtilSystemWindows.h b/tools/lldb-mi/MIUtilSystemWindows.h
new file mode 100644
index 000000000000..c0d8b543a2f0
--- /dev/null
+++ b/tools/lldb-mi/MIUtilSystemWindows.h
@@ -0,0 +1,56 @@
+//===-- MIUtilSystemWindows.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilSystemWindows.h
+//
+// Overview: CMIUtilSystemWindows interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+#pragma once
+
+#if defined( _MSC_VER )
+
+// In-house headers:
+#include "MIUtilString.h"
+
+//++ ============================================================================
+// Details: MI common code utility class. Used to set or retrieve information
+// about the current system or user.
+// *** If you change, remove or add functionality it must be replicated
+// *** for the all platforms supported; Windows, OSX, LINUX
+// Gotchas: None.
+// Authors: Illya Rudkin 29/01/2014.
+// Changes: None.
+//--
+class CMIUtilSystemWindows
+{
+// Methods:
+public:
+ /* ctor */ CMIUtilSystemWindows( void );
+
+ bool GetOSErrorMsg( const MIint vError, CMIUtilString & vrwErrorMsg ) const;
+ CMIUtilString GetOSLastError( void ) const;
+ bool GetExecutablesPath( CMIUtilString & vrwFileNamePath ) const;
+ bool GetLogFilesPath( CMIUtilString & vrwFileNamePath ) const;
+
+// Overrideable:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMIUtilSystemWindows( void );
+};
+
+typedef CMIUtilSystemWindows CMIUtilSystem;
+
+#endif // #if defined( _MSC_VER )
diff --git a/tools/lldb-mi/MIUtilTermios.cpp b/tools/lldb-mi/MIUtilTermios.cpp
new file mode 100644
index 000000000000..f026436e3fa3
--- /dev/null
+++ b/tools/lldb-mi/MIUtilTermios.cpp
@@ -0,0 +1,69 @@
+//===-- MIUtilTermios.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilTermios.cpp
+//
+// Overview: Terminal setting termios functions.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third party headers:
+#include <stdlib.h>
+
+// In-house headers:
+#include "MIUtilTermios.h"
+#include "Platform.h"
+
+namespace MIUtilTermios
+{
+// Instantiations:
+static bool g_bOldStdinTermiosIsValid = false; // True = yes valid, false = no valid
+static struct termios g_sOldStdinTermios;
+
+//++ ------------------------------------------------------------------------------------
+// Details: Reset the terminal settings. This function is added as an ::atexit handler
+// to make sure we clean up. See StdinTerminosSet().
+// Type: Global function.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void StdinTermiosReset( void )
+{
+ if( g_bOldStdinTermiosIsValid )
+ {
+ g_bOldStdinTermiosIsValid = false;
+ ::tcsetattr( STDIN_FILENO, TCSANOW, &g_sOldStdinTermios );
+ }
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set the terminal settings function. StdinTermiosReset() is called when to
+// reset to this to before and application exit.
+// Type: Global function.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void StdinTermiosSet( void )
+{
+ if( ::tcgetattr( STDIN_FILENO, &g_sOldStdinTermios ) == 0 )
+ {
+ g_bOldStdinTermiosIsValid = true;
+ ::atexit( StdinTermiosReset );
+ }
+}
+
+} // namespace MIUtilTermios
diff --git a/tools/lldb-mi/MIUtilTermios.h b/tools/lldb-mi/MIUtilTermios.h
new file mode 100644
index 000000000000..b38f367b68ea
--- /dev/null
+++ b/tools/lldb-mi/MIUtilTermios.h
@@ -0,0 +1,30 @@
+//===-- MIUtilTermios.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilTermios.h
+//
+// Overview: Terminal setting termios functions.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+namespace MIUtilTermios
+{
+
+extern void StdinTermiosReset( void );
+extern void StdinTermiosSet( void );
+
+} // MIUtilTermios
diff --git a/tools/lldb-mi/MIUtilThreadBaseStd.cpp b/tools/lldb-mi/MIUtilThreadBaseStd.cpp
new file mode 100644
index 000000000000..38f3eb4fae3b
--- /dev/null
+++ b/tools/lldb-mi/MIUtilThreadBaseStd.cpp
@@ -0,0 +1,339 @@
+//===-- MIUtilThreadBaseStd.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilThreadBaseStd.cpp
+//
+// Overview: CMIUtilThread implementation.
+// CMIUtilThreadActiveObjBase implementation.
+// CMIUtilThreadMutex implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+// Third Party Headers:
+#include <assert.h>
+
+// In-house headers:
+#include "MIUtilThreadBaseStd.h"
+#include "MICmnThreadMgrStd.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: Constructor.
+// Type: None.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilThreadActiveObjBase::CMIUtilThreadActiveObjBase( void )
+: m_references( 0 )
+, m_bHasBeenKilled( false )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Destructor.
+// Type: None.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilThreadActiveObjBase::~CMIUtilThreadActiveObjBase( void )
+{
+ // Make sure our thread is not alive before we die
+ m_thread.Join();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Check if an object is already running.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilThreadActiveObjBase::ThreadIsActive( void )
+{
+ // Create a new thread to occupy this threads Run() function
+ return m_thread.IsActive();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set up *this thread.
+// Type: Mrthod.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilThreadActiveObjBase::ThreadExecute( void )
+{
+ // Create a new thread to occupy this threads Run() function
+ return m_thread.Start( ThreadEntry, this );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Aquire a reference to CMIUtilThreadActiveObjBase.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilThreadActiveObjBase::Acquire( void )
+{
+ // Access to this function is serial
+ CMIUtilThreadLock serial( m_mutex );
+
+ // >0 == *this thread is alive
+ m_references++;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release a reference to CMIUtilThreadActiveObjBase.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilThreadActiveObjBase::Release( void )
+{
+ // Access to this function is serial
+ CMIUtilThreadLock serial( m_mutex );
+
+ // 0 == kill off *this thread
+ m_references--;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Force this thread to stop, regardless of references
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilThreadActiveObjBase::ThreadKill( void )
+{
+ // Access to this function is serial
+ CMIUtilThreadLock serial( m_mutex );
+
+ // Set this thread to killed status
+ m_bHasBeenKilled = true;
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Proxy to thread join.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilThreadActiveObjBase::ThreadJoin( void )
+{
+ return m_thread.Join();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: This function is the entry point of this object thread.
+// It is a trampoline to an instances operation manager.
+// Type: Static method.
+// Args: vpThisClass - (R) From the system (our CMIUtilThreadActiveObjBase from the ctor).
+// Return: MIuint - 0 = success.
+// Throws: None.
+//--
+MIuint CMIUtilThreadActiveObjBase::ThreadEntry( void * vpThisClass )
+{
+ // The argument is a pointer to a CMIUtilThreadActiveObjBase class
+ // as passed from the initialize function, so we can safely cast it.
+ assert( vpThisClass != nullptr );
+ CMIUtilThreadActiveObjBase * pActive = reinterpret_cast< CMIUtilThreadActiveObjBase * >( vpThisClass );
+
+ // Start the management routine of this object
+ pActive->ThreadManage();
+
+ // Thread death
+ return 0;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: This function forms a small management routine, to handle the thread's running.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMIUtilThreadActiveObjBase::ThreadManage( void )
+{
+ bool bAlive = true;
+
+ // Infinite loop
+ while( bAlive )
+ {
+ // Scope the lock while we access m_isDying
+ {
+ // Lock down access to the interface
+ CMIUtilThreadLock serial( m_mutex );
+
+ // Quit the run loop if we are dying
+ if( m_references == 0 )
+ break;
+ }
+ // Execute the run routine
+ if( !ThreadRun( bAlive ) )
+ // Thread's run function failed (MIstatus::failure)
+ break;
+
+ // We will die if we have been signaled to die
+ bAlive &= !m_bHasBeenKilled;
+ }
+
+ // Execute the finish routine just before we die
+ // to give the object a chance to clean up
+ ThreadFinish();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//
+CMIUtilThread::CMIUtilThread( void )
+: m_pThread( nullptr )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilThread destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilThread::~CMIUtilThread( void )
+{
+ Join();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Wait for thread to stop.
+// Type: Method.
+// Args: None.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilThread::Join( void )
+{
+ if( m_pThread != nullptr )
+ {
+ // Wait for this thread to die
+ m_pThread->join();
+
+ // Scope the thread lock while we modify the pointer
+ {
+ CMIUtilThreadLock _lock( m_mutex );
+ delete m_pThread;
+ m_pThread = nullptr;
+ }
+ }
+
+ return MIstatus::success;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Is the thread doing work.
+// Type: Method.
+// Args: None.
+// Return: bool - True = Yes active, false = not active.
+// Throws: None.
+//--
+bool CMIUtilThread::IsActive( void )
+{
+ // Lock while we access the thread pointer
+ CMIUtilThreadLock _lock( m_mutex );
+ if( m_pThread == nullptr )
+ return false;
+ else
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Set up *this thread.
+// Type: Method.
+// Args: vpFn (R) - Function pointer to thread's main function.
+// vpArg (R) - Pointer arguments to pass to the thread.
+// Return: MIstatus::success - Functional succeeded.
+// MIstatus::failure - Functional failed.
+// Throws: None.
+//--
+bool CMIUtilThread::Start( FnThreadProc vpFn, void * vpArg )
+{
+ // Create the std thread, which starts immediately
+ m_pThread = new std::thread( vpFn, vpArg );
+
+ // We expect to always be able to create one
+ assert( m_pThread != nullptr );
+
+ return MIstatus::success;
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: Take resource.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMIUtilThreadMutex::Lock( void )
+{
+ m_mutex.lock();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release resource.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMIUtilThreadMutex::Unlock( void )
+{
+ m_mutex.unlock();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Take resource if available. Immediately return in either case.
+// Type: Method.
+// Args: None.
+// Return: True - mutex has been locked.
+// False - mutex could not be locked.
+// Throws: None.
+//--
+bool CMIUtilThreadMutex::TryLock( void )
+{
+ return m_mutex.try_lock();
+}
+
diff --git a/tools/lldb-mi/MIUtilThreadBaseStd.h b/tools/lldb-mi/MIUtilThreadBaseStd.h
new file mode 100644
index 000000000000..277e14c0fc88
--- /dev/null
+++ b/tools/lldb-mi/MIUtilThreadBaseStd.h
@@ -0,0 +1,170 @@
+//===-- MIUtilThreadBaseStd.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilThreadBaseStd.h
+//
+// Overview: CMIUtilThread interface.
+// CMIUtilThreadActiveObjBase interface.
+// CMIUtilThreadMutex interface.
+// CMIUtilThreadLock interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// Third party headers:
+#ifdef _MSC_VER
+#include <eh.h>
+#endif // _MSC_VER
+#include <thread>
+#include <mutex>
+
+// In-house headers:
+#include "MIDataTypes.h"
+#include "MIUtilString.h"
+
+//++ ============================================================================
+// Details: MI common code utility class. Handle thread mutual exclusion.
+// Embed Mutexes in your Active Object and then use them through Locks.
+// Gotchas: None.
+// Authors: Aidan Dodds 10/03/2014.
+// Changes: None.
+//--
+class CMIUtilThreadMutex
+{
+ // Methods:
+public:
+ /* ctor */ CMIUtilThreadMutex( void ) { };
+ //
+ void Lock( void ); // Wait until mutex can be obtained
+ void Unlock( void ); // Release the mutex
+ bool TryLock( void ); // Gain the lock if available
+
+// Overrideable:
+public:
+ // From CMICmnBase
+ /* dtor */ virtual ~CMIUtilThreadMutex( void ) { };
+
+// Attributes:
+private:
+ std::recursive_mutex m_mutex;
+};
+
+//++ ============================================================================
+// Details: MI common code utility class. Thread object.
+// Gotchas: None.
+// Authors: Aidan Dodds 10/03/2014.
+// Changes: None.
+//--
+class CMIUtilThread
+{
+// Typedef:
+public:
+ typedef MIuint (* FnThreadProc) (void * vpThisClass);
+
+// Methods:
+public:
+ /* ctor */ CMIUtilThread( void );
+ //
+ bool Start( FnThreadProc vpFn, void * vpArg ); // Start execution of this thread
+ bool Join( void ); // Wait for this thread to stop
+ bool IsActive( void ); // Returns true if this thread is running
+
+// Overrideable:
+public:
+ /* dtor */ virtual ~CMIUtilThread( void );
+
+// Methods:
+private:
+ CMIUtilThreadMutex m_mutex;
+ std::thread * m_pThread;
+};
+
+//++ ============================================================================
+// Details: MI common code utility class. Base class for a worker thread active
+// object. Runs an 'captive thread'.
+// Gotchas: None.
+// Authors: Aidan Dodds 10/03/2014..
+// Changes: None.
+//--
+class CMIUtilThreadActiveObjBase
+{
+// Methods:
+public:
+ /* ctor */ CMIUtilThreadActiveObjBase( void );
+ //
+ bool Acquire( void ); // Obtain a reference to this object
+ bool Release( void ); // Release a reference to this object
+ bool ThreadIsActive( void ); // Return true if this object is running
+ bool ThreadJoin( void ); // Wait for this thread to stop running
+ bool ThreadKill( void ); // Force this thread to stop, regardless of references
+ bool ThreadExecute( void ); // Start this objects execution in another thread
+ void ThreadManage( void );
+
+// Overrideable:
+public:
+ /* dtor */ virtual ~CMIUtilThreadActiveObjBase( void );
+ //
+ // Each thread object must supple a unique name that can be used to locate it
+ virtual const CMIUtilString & ThreadGetName( void ) const = 0;
+
+// Statics:
+protected:
+ static MIuint ThreadEntry( void * vpThisClass ); // Thread entry point
+
+// Overrideable:
+protected:
+ virtual bool ThreadRun( bool &vrIsAlive ) = 0; // Call the main worker method
+ virtual bool ThreadFinish( void ) = 0; // Finish of what you were doing
+
+// Attributes:
+protected:
+ volatile MIuint m_references; // Stores the current lifetime state of this thread, 0 = running, > 0 = shutting down
+ volatile bool m_bHasBeenKilled; // Set to true when this thread has been killed
+ CMIUtilThread m_thread; // The execution thread
+ CMIUtilThreadMutex m_mutex; // This mutex allows us to safely communicate with this thread object across the interface from multiple threads
+};
+
+//++ ============================================================================
+// Details: MI common code utility class. Handle thread resource locking.
+// Put Locks inside all the methods of your Active Object that access
+// data shared with the captive thread.
+// Gotchas: None.
+// Authors: Aidan Dodds 10/03/2014.
+// Changes: None.
+//--
+class CMIUtilThreadLock
+{
+// Methods:
+public:
+ /* ctor */
+ CMIUtilThreadLock( CMIUtilThreadMutex & vMutex )
+ : m_rMutex( vMutex )
+ {
+ m_rMutex.Lock();
+ }
+
+// Overrideable:
+public:
+ /* dtor */
+ virtual ~CMIUtilThreadLock( void )
+ {
+ m_rMutex.Unlock();
+ }
+
+// Attributes:
+private:
+ CMIUtilThreadMutex & m_rMutex;
+};
diff --git a/tools/lldb-mi/MIUtilVariant.cpp b/tools/lldb-mi/MIUtilVariant.cpp
new file mode 100644
index 000000000000..1c9ea1c9697f
--- /dev/null
+++ b/tools/lldb-mi/MIUtilVariant.cpp
@@ -0,0 +1,392 @@
+//===-- MIUtilVariant.cpp----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilVariant.cpp
+//
+// Overview: CMIUtilVariant implementation.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Gotchas: See CMIUtilVariant class description.
+//
+// Copyright: None.
+//--
+
+// In-house headers:
+#include "MIUtilVariant.h"
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObjectBase constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant::CDataObjectBase::CDataObjectBase( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObjectBase copy constructor.
+// Type: Method.
+// Args: vrOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant::CDataObjectBase::CDataObjectBase( const CDataObjectBase & vrOther )
+{
+ MIunused( vrOther );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObjectBase copy constructor.
+// Type: Method.
+// Args: vrOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant::CDataObjectBase::CDataObjectBase( CDataObjectBase & vrOther )
+{
+ MIunused( vrOther );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObjectBase move constructor.
+// Type: Method.
+// Args: vrwOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant::CDataObjectBase::CDataObjectBase( CDataObjectBase && vrwOther )
+{
+ MIunused( vrwOther );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObjectBase destructor.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant::CDataObjectBase::~CDataObjectBase( void )
+{
+ Destroy();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObjectBase copy assignment.
+// Type: Method.
+// Args: vrOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant::CDataObjectBase & CMIUtilVariant::CDataObjectBase::operator= ( const CDataObjectBase & vrOther )
+{
+ Copy( vrOther );
+ return *this;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObjectBase move assignment.
+// Type: Method.
+// Args: vrwOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant::CDataObjectBase & CMIUtilVariant::CDataObjectBase::operator= ( CDataObjectBase && vrwOther )
+{
+ Copy( vrwOther );
+ vrwOther.Destroy();
+ return *this;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Create a new copy of *this class.
+// Type: Overrideable.
+// Args: None.
+// Return: CDataObjectBase * - Pointer to a new object.
+// Throws: None.
+//--
+CMIUtilVariant::CDataObjectBase * CMIUtilVariant::CDataObjectBase::CreateCopyOfSelf( void )
+{
+ // Override to implement copying of variant's data object
+ return new CDataObjectBase();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine if *this object is a derived from CDataObjectBase.
+// Type: Overrideable.
+// Args: None.
+// Return: bool - True = *this is derived from CDataObjectBase, false = *this is instance of the this base class.
+// Throws: None.
+//--
+bool CMIUtilVariant::CDataObjectBase::GetIsDerivedClass( void ) const
+{
+ // Override to in the derived class and return true
+ return false;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Perform a bitwise copy of *this object.
+// Type: Overrideable.
+// Args: vrOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+void CMIUtilVariant::CDataObjectBase::Copy( const CDataObjectBase & vrOther )
+{
+ // Override to implement
+ MIunused( vrOther );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release any resources used by *this object.
+// Type: Overrideable.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMIUtilVariant::CDataObjectBase::Destroy( void )
+{
+ // Do nothing - override to implement
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObject copy constructor.
+// Type: Method.
+// Args: T - The object's type.
+// vrOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+template< typename T >
+CMIUtilVariant::CDataObject< T >::CDataObject( const CDataObject & vrOther )
+{
+ if( this == &vrOther )
+ return;
+ Copy( vrOther );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObject copy constructor.
+// Type: Method.
+// Args: T - The object's type.
+// vrOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+template< typename T >
+CMIUtilVariant::CDataObject< T >::CDataObject( CDataObject & vrOther )
+{
+ if( this == &vrOther )
+ return;
+ Copy( vrOther );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObject move constructor.
+// Type: Method.
+// Args: T - The object's type.
+// vrwOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+template< typename T >
+CMIUtilVariant::CDataObject< T >::CDataObject( CDataObject && vrwOther )
+{
+ if( this == &vrwOther )
+ return;
+ Copy( vrwOther );
+ vrwOther.Destroy();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObject copy assignment.
+// Type: Method.
+// Args: T - The object's type.
+// vrOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+template< typename T >
+CMIUtilVariant::CDataObject< T > & CMIUtilVariant::CDataObject< T >::operator= ( const CDataObject & vrOther )
+{
+ if( this == &vrOther )
+ return *this;
+ Copy( vrOther );
+ return *this;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObject move assignment.
+// Type: Method.
+// Args: T - The object's type.
+// vrwOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+template< typename T >
+CMIUtilVariant::CDataObject< T > & CMIUtilVariant::CDataObject< T >::operator= ( CDataObject && vrwOther )
+{
+ if( this == &vrwOther )
+ return *this;
+ Copy( vrwOther );
+ vrwOther.Destroy();
+ return *this;
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilVariant constructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant::CMIUtilVariant( void )
+: m_pDataObject( nullptr )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilVariant copy constructor.
+// Type: Method.
+// Args: vrOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant::CMIUtilVariant( const CMIUtilVariant & vrOther )
+: m_pDataObject( nullptr )
+{
+ if( this == &vrOther )
+ return;
+
+ Copy( vrOther );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilVariant copy constructor.
+// Type: Method.
+// Args: vrOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant::CMIUtilVariant( CMIUtilVariant & vrOther )
+: m_pDataObject( nullptr )
+{
+ if( this == &vrOther )
+ return;
+
+ Copy( vrOther );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilVariant move constructor.
+// Type: Method.
+// Args: vrwOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant::CMIUtilVariant( CMIUtilVariant && vrwOther )
+: m_pDataObject( nullptr )
+{
+ if( this == &vrwOther )
+ return;
+
+ Copy( vrwOther );
+ vrwOther.Destroy();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilVariant destructor.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant::~CMIUtilVariant( void )
+{
+ Destroy();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilVariant copy assignment.
+// Type: Method.
+// Args: vrOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant & CMIUtilVariant::operator= ( const CMIUtilVariant & vrOther )
+{
+ if( this == &vrOther )
+ return *this;
+
+ Copy( vrOther );
+ return *this;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilVariant move assignment.
+// Type: Method.
+// Args: vrwOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilVariant & CMIUtilVariant::operator= ( CMIUtilVariant && vrwOther )
+{
+ if( this == &vrwOther )
+ return *this;
+
+ Copy( vrwOther );
+ vrwOther.Destroy();
+ return *this;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release the resources used by *this object.
+// Type: Method.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+void CMIUtilVariant::Destroy( void )
+{
+ if( m_pDataObject != nullptr )
+ delete m_pDataObject;
+ m_pDataObject = nullptr;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Bitwise copy another data object to *this variant object.
+// Type: Method.
+// Args: vrOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+void CMIUtilVariant::Copy( const CMIUtilVariant & vrOther )
+{
+ Destroy();
+
+ if( vrOther.m_pDataObject != nullptr )
+ {
+ m_pDataObject = vrOther.m_pDataObject->CreateCopyOfSelf();
+ }
+}
+
diff --git a/tools/lldb-mi/MIUtilVariant.h b/tools/lldb-mi/MIUtilVariant.h
new file mode 100644
index 000000000000..3cb59796e5c0
--- /dev/null
+++ b/tools/lldb-mi/MIUtilVariant.h
@@ -0,0 +1,288 @@
+//===-- MIUtilVariant.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//++
+// File: MIUtilVariant.h
+//
+// Overview: CMIUtilVariant interface.
+//
+// Environment: Compilers: Visual C++ 12.
+// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
+// Libraries: See MIReadmetxt.
+//
+// Gotchas: See CMIUtilVariant class description.
+//
+// Copyright: None.
+//--
+
+#pragma once
+
+// In-house headers:
+#include "MIDataTypes.h"
+
+//++ ============================================================================
+// Details: MI common code utility class. The class implements behaviour of a
+// variant object which holds any data object of type T. A copy of the
+// data object specified is made and stored in *this wrapper. When the
+// *this object is destroyed the data object hold within calls its
+// destructor should it have one.
+// Gotchas: None.
+// Authors: Illya Rudkin 18/06/2014.
+// Changes: None.
+//--
+class CMIUtilVariant
+{
+// Methods:
+public:
+ /* ctor */ CMIUtilVariant( void );
+ /* ctor */ CMIUtilVariant( const CMIUtilVariant & vrOther );
+ /* ctor */ CMIUtilVariant( CMIUtilVariant & vrOther );
+ /* ctor */ CMIUtilVariant( CMIUtilVariant && vrwOther );
+ /* dtor */ ~CMIUtilVariant( void );
+
+ template< typename T >
+ void Set( const T & vArg );
+ template< typename T >
+ T * Get( void ) const;
+
+ CMIUtilVariant & operator= ( const CMIUtilVariant & vrOther );
+ CMIUtilVariant & operator= ( CMIUtilVariant && vrwOther );
+
+// Classes:
+private:
+ //++ ----------------------------------------------------------------------
+ // Details: Base class wrapper to hold the variant's data object when
+ // assigned to it by the Set() function. Do not use the CDataObjectBase
+ // to create objects, use only CDataObjectBase derived objects,
+ // see CDataObject() class.
+ //--
+ class CDataObjectBase
+ {
+ // Methods:
+ public:
+ /* ctor */ CDataObjectBase( void );
+ /* ctor */ CDataObjectBase( const CDataObjectBase & vrOther );
+ /* ctor */ CDataObjectBase( CDataObjectBase & vrOther );
+ /* ctor */ CDataObjectBase( CDataObjectBase && vrwOther );
+ //
+ CDataObjectBase & operator= ( const CDataObjectBase & vrOther ) ;
+ CDataObjectBase & operator= ( CDataObjectBase && vrwOther ) ;
+
+ // Overrideable:
+ public:
+ virtual ~CDataObjectBase( void );
+ virtual CDataObjectBase * CreateCopyOfSelf( void );
+ virtual bool GetIsDerivedClass( void ) const;
+
+ // Overrideable:
+ protected:
+ virtual void Copy( const CDataObjectBase & vrOther );
+ virtual void Destroy( void );
+ };
+
+ //++ ----------------------------------------------------------------------
+ // Details: Derived from CDataObjectBase, this class is the wrapper for the
+ // data object as it has an aggregate of type T which is a copy
+ // of the data object assigned to the variant object.
+ //--
+ template< typename T >
+ class CDataObject : public CDataObjectBase
+ {
+ // Methods:
+ public:
+ /* ctor */ CDataObject( void );
+ /* ctor */ CDataObject( const T & vArg );
+ /* ctor */ CDataObject( const CDataObject & vrOther );
+ /* ctor */ CDataObject( CDataObject & vrOther );
+ /* ctor */ CDataObject( CDataObject && vrwOther );
+ //
+ CDataObject & operator= ( const CDataObject & vrOther );
+ CDataObject & operator= ( CDataObject && vrwOther );
+ //
+ T & GetDataObject( void );
+
+ // Overridden:
+ public:
+ // From CDataObjectBase
+ virtual ~CDataObject( void );
+ virtual CDataObjectBase * CreateCopyOfSelf( void );
+ virtual bool GetIsDerivedClass( void ) const;
+
+ // Overridden:
+ private:
+ // From CDataObjectBase
+ virtual void Copy( const CDataObject & vrOther );
+ virtual void Destroy( void );
+
+ // Attributes:
+ private:
+ T m_dataObj;
+ };
+
+// Methods
+private:
+ void Destroy( void );
+ void Copy( const CMIUtilVariant & vrOther );
+
+// Attributes:
+private:
+ CDataObjectBase * m_pDataObject;
+};
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObject constructor.
+// Type: Method.
+// Args: T - The object's type.
+// Return: None.
+// Throws: None.
+//--
+template< typename T >
+CMIUtilVariant::CDataObject< T >::CDataObject( void )
+{
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObject constructor.
+// Type: Method.
+// Args: T - The object's type.
+// vArg - (R) The data object to be stored in the variant object.
+// Return: None.
+// Throws: None.
+//--
+template< typename T >
+CMIUtilVariant::CDataObject< T >::CDataObject( const T & vArg )
+{
+ m_dataObj = vArg;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: CDataObject destructor.
+// Type: Overridden.
+// Args: T - The object's type.
+// Return: None.
+// Throws: None.
+//--
+template< typename T >
+CMIUtilVariant::CDataObject< T >::~CDataObject( void )
+{
+ Destroy();
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the data object hold by *this object wrapper.
+// Type: Method.
+// Args: T - The object's type.
+// Return: T & - Reference to the data object.
+// Throws: None.
+//--
+template< typename T >
+T & CMIUtilVariant::CDataObject< T >::GetDataObject( void )
+{
+ return m_dataObj;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Create a new copy of *this class.
+// Type: Overridden.
+// Args: T - The object's type.
+// Return: CDataObjectBase * - Pointer to a new object.
+// Throws: None.
+//--
+template< typename T >
+CMIUtilVariant::CDataObjectBase * CMIUtilVariant::CDataObject< T >::CreateCopyOfSelf( void )
+{
+ CDataObject * pCopy = new CDataObject< T >( m_dataObj );
+
+ return pCopy;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Determine if *this object is a derived from CDataObjectBase.
+// Type: Overridden.
+// Args: T - The object's type.
+// Return: bool - True = *this is derived from CDataObjectBase
+// - False = *this is an instance of the base class.
+// Throws: None.
+//--
+template< typename T >
+bool CMIUtilVariant::CDataObject< T >::GetIsDerivedClass( void ) const
+{
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Perform a bitwise copy of *this object.
+// Type: Overridden.
+// Args: T - The object's type.
+// vrOther - (R) The other object.
+// Return: None.
+// Throws: None.
+//--
+template< typename T >
+void CMIUtilVariant::CDataObject< T >::Copy( const CDataObject & vrOther )
+{
+ CDataObjectBase::Copy( vrOther );
+ m_dataObj = vrOther.m_dataObj;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Release any resources used by *this object.
+// Type: Overridden.
+// Args: None.
+// Return: None.
+// Throws: None.
+//--
+template< typename T >
+void CMIUtilVariant::CDataObject< T >::Destroy( void )
+{
+ CDataObjectBase::Destroy();
+}
+
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------
+
+//++ ------------------------------------------------------------------------------------
+// Details: Assign to the variant an object of a specified type.
+// Type: Template method.
+// Args: T - The object's type.
+// vArg - (R) The object to store.
+// Return: None.
+// Throws: None.
+//--
+template< typename T >
+void CMIUtilVariant::Set( const T & vArg )
+{
+ m_pDataObject = new CDataObject< T >( vArg );
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Retrieve the data object from *this variant.
+// Type: Template method.
+// Args: T - The object's type.
+// Return: T * - Pointer the data object, NULL = data object not assigned to *this variant.
+// Throws: None.
+//--
+template< typename T >
+T * CMIUtilVariant::Get( void ) const
+{
+ if( (m_pDataObject != nullptr) && m_pDataObject->GetIsDerivedClass() )
+ {
+ CDataObject< T > * pDataObj = static_cast< CDataObject< T > * >( m_pDataObject );
+ return &pDataObj->GetDataObject();
+ }
+
+ // Do not use a CDataObjectBase object, use only CDataObjectBase derived objects
+ return nullptr;
+}
+
diff --git a/tools/lldb-mi/Platform.cpp b/tools/lldb-mi/Platform.cpp
new file mode 100644
index 000000000000..c0208b3518c0
--- /dev/null
+++ b/tools/lldb-mi/Platform.cpp
@@ -0,0 +1,109 @@
+//===-- Platform.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// this file is only relevant for Visual C++
+#if defined( _MSC_VER )
+
+#include <process.h>
+#include <assert.h>
+
+#include "Platform.h"
+
+// the control handler or SIGINT handler
+static sighandler_t _ctrlHandler = NULL;
+
+// the default console control handler
+BOOL
+WINAPI CtrlHandler (DWORD ctrlType)
+{
+ if ( _ctrlHandler != NULL )
+ {
+ _ctrlHandler( 0 );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int
+ioctl (int d, int request, ...)
+{
+ switch ( request )
+ {
+ // request the console windows size
+ case ( TIOCGWINSZ ):
+ {
+ va_list vl;
+ va_start(vl,request);
+ // locate the window size structure on stack
+ winsize *ws = va_arg(vl, winsize*);
+ // get screen buffer information
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if ( GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &info ) == TRUE )
+ // fill in the columns
+ ws->ws_col = info.dwMaximumWindowSize.X;
+ va_end(vl);
+ return 0;
+ }
+ break;
+ default:
+ assert( !"Not implemented!" );
+ }
+ return -1;
+}
+
+int
+kill (pid_t pid, int sig)
+{
+ // is the app trying to kill itself
+ if ( pid == getpid( ) )
+ exit( sig );
+ //
+ assert( !"Not implemented!" );
+ return -1;
+}
+
+int
+tcsetattr (int fd, int optional_actions, const struct termios *termios_p)
+{
+ assert( !"Not implemented!" );
+ return -1;
+}
+
+int
+tcgetattr (int fildes, struct termios *termios_p)
+{
+// assert( !"Not implemented!" );
+ // error return value (0=success)
+ return -1;
+}
+
+sighandler_t
+signal (int sig, sighandler_t sigFunc)
+{
+ switch ( sig )
+ {
+ case ( SIGINT ):
+ {
+ _ctrlHandler = sigFunc;
+ SetConsoleCtrlHandler( CtrlHandler, TRUE );
+ }
+ break;
+ case ( SIGPIPE ):
+ case ( SIGWINCH ):
+ case ( SIGTSTP ):
+ case ( SIGCONT ):
+ // ignore these for now
+ break;
+ default:
+ assert( !"Not implemented!" );
+ }
+ return 0;
+}
+
+#endif
diff --git a/tools/lldb-mi/Platform.h b/tools/lldb-mi/Platform.h
new file mode 100644
index 000000000000..443eedcef1ee
--- /dev/null
+++ b/tools/lldb-mi/Platform.h
@@ -0,0 +1,109 @@
+//===-- Platform.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#pragma once
+
+#if defined( _MSC_VER )
+
+ // this will stop signal.h being included
+ #define _INC_SIGNAL
+
+ #include <io.h>
+ #include <eh.h>
+ #include <inttypes.h>
+ #include <lldb/Host/windows/Windows.h>
+ #include <lldb/Host/HostGetOpt.h>
+
+ // This is not used by MI
+ struct timeval
+ {
+ long tv_sec;
+ long tv_usec;
+ };
+
+ struct winsize
+ {
+ long ws_col;
+ };
+
+ typedef unsigned char cc_t;
+ typedef unsigned int speed_t;
+ typedef unsigned int tcflag_t;
+
+ // fcntl.h // This is not used by MI
+ #define O_NOCTTY 0400
+
+ // ioctls.h
+ #define TIOCGWINSZ 0x5413
+
+ // tcsetattr arguments
+ #define TCSANOW 0
+
+ #define NCCS 32
+ struct termios
+ {
+ tcflag_t c_iflag; // input mode flags
+ tcflag_t c_oflag; // output mode flags
+ tcflag_t c_cflag; // control mode flags
+ tcflag_t c_lflag; // local mode flags
+ cc_t c_line; // line discipline
+ cc_t c_cc[NCCS]; // control characters
+ speed_t c_ispeed; // input speed
+ speed_t c_ospeed; // output speed
+ };
+
+ typedef long pid_t;
+
+ #define STDIN_FILENO 0
+ #define PATH_MAX MAX_PATH
+ #define snprintf _snprintf
+
+ extern int ioctl( int d, int request, ... );
+ extern int kill ( pid_t pid, int sig );
+ extern int tcsetattr( int fd, int optional_actions, const struct termios *termios_p );
+ extern int tcgetattr( int fildes, struct termios *termios_p );
+
+ // signal handler function pointer type
+ typedef void (*sighandler_t)(int);
+
+ // CODETAG_IOR_SIGNALS
+ // signal.h
+ #define SIGINT 2 // Terminal interrupt signal
+ #define SIGQUIT 3 // Terminal quit signal
+ #define SIGKILL 9 // Kill (cannot be caught or ignored)
+ #define SIGPIPE 13 // Write on a pipe with no one to read it
+ #define SIGCONT 18 // Continue executing, if stopped.
+ #define SIGTSTP 20 // Terminal stop signal
+ #define SIGSTOP 23 // Stop executing (cannot be caught or ignored)
+ #define SIGWINCH 28 // (== SIGVTALRM)
+ #define SIG_DFL ( (sighandler_t) -1 ) // Default handler
+ #define SIG_IGN ( (sighandler_t) -2 ) // Ignored
+
+ extern sighandler_t signal( int sig, sighandler_t );
+
+#else
+
+ #include <inttypes.h>
+
+ #include <getopt.h>
+ #include <libgen.h>
+ #include <sys/ioctl.h>
+ #include <termios.h>
+ #include <unistd.h>
+
+ #include <histedit.h>
+ #include <pthread.h>
+ #include <sys/time.h>
+
+ #if defined(__FreeBSD__)
+ #include <readline/readline.h>
+ #else
+ #include <editline/readline.h>
+ #endif
+
+#endif
diff --git a/tools/lldb-platform/lldb-platform.cpp b/tools/lldb-platform/lldb-platform.cpp
index e18ebabc784d..0ab292aa4afb 100644
--- a/tools/lldb-platform/lldb-platform.cpp
+++ b/tools/lldb-platform/lldb-platform.cpp
@@ -11,7 +11,9 @@
// C Includes
#include <errno.h>
-#include "lldb/Host/HostGetOpt.h"
+#if defined(__APPLE__)
+#include <netinet/in.h>
+#endif
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
@@ -27,6 +29,7 @@
#include "lldb/Core/ConnectionMachPort.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/StreamFile.h"
+#include "lldb/Host/HostGetOpt.h"
#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -286,7 +289,7 @@ main (int argc, char *argv[])
bool done = false;
while (!interrupt && !done)
{
- if (!gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done))
+ if (gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done) != GDBRemoteCommunication::PacketResult::Success)
break;
}